2015-07-16 1 views
0

J'ai essayé certains appels ASM à partir de C et vice versa. Cela a fonctionné parfaitement au moins pour l'instant mais j'ai des questions. Voici mon code:A propos de l'appel de la fonction C à partir de l'assemblage et vice versa

test.S suivi:

.text    

.global _start 


.global _main  
.type _main, @function 


.global writeMe        
.type writeMe, @function  

_start: 

     #; Write hello world for 5 times. 
    #; Jump exit and call C function after that. 
    #; C function calls writeMe assembly function 
    #; Exit with syscall 

    xorl %ecx, %ecx    #; ecx = 0 
    call _get_eip   #; get eip without labels. Just for research. 
    pushl %eax    #; push to stack 
    incl %ecx    #; ++ecx 
    pushl %ecx    #; push to stack 

    movl $len,%edx   #; tell length of string 
    movl $msg,%ecx    #; tell string position 
    movl $1,%ebx     #; fd = stdout 
    movl $4,%eax     #; syscall = write 
    int  $0x80    #; perform call 

    popl %ecx    #; pop counter 

    movl %ecx, %eax    #; eax = ecx 
    cmpl $0x5, %eax    #; compare 0x5 and eax 
    je _exit    #; eax == 0x5, jump exit 

    _jmp: 
     popl %eax   #; pop instruction pointer 
     jmpl %eax   #; jmp 

    _exit: 
     call _main   #; call C function 
     movl $0,%ebx    #; EXIT_SUCCESS 
     movl $1,%eax    #; syscall = exit 
     int  $0x80    #; perform call 
     ret 

_get_eip:     #; function for getting eip 
    popl %eax    #; pop eip 
    pushl %eax    #; push again to return 
    ret     #; return location 

writeMe:     #; function for writing, called from C 
    popl (__eip)    #; pop return location 
    popl %ecx    #; pop first argument, msg 
    popl %edx    #; pop second argument, len 

    movl $1, %ebx    #; fd = stdout 
    movl $4, %eax    #; syscall = write 
    int $0x80    #; perform call 

    pushl (__eip)    #; push return location 
    ret     #; return location 

writeMe2:     #; function for writing, called from C 
    popl %ecx    #; pop return location 
    popl %ecx    #; pop first argument, msg 
    popl %edx    #; pop second argument, len 

    movl $1, %ebx    #; fd = stdout 
    movl $4, %eax    #; syscall = write 
    int $0x80    #; perform call 

    subl $0x0C, %esp   #; restore stack 
    ret 

.data       

__eip: .long 

msg: 
    .ascii "Hello, world!\n\0" 
    len = . - msg     

MAIN.C suivi:

extern void writeMe(const char *msg, int len); 

int _strlen(const char *msg) { 
    int _len = 0; 
    while (*msg++ != 0x0) 
     _len++; 
    return _len; 
} 

void _main() { 

    const char * szmsg = "Hello, world!\n"; 
    writeMe(szmsg, _strlen(szmsg)); 
} 

Ma sortie est comme ce que je pensais.

Bonjour, monde!
Bonjour, monde!
Bonjour, monde!
Bonjour, monde!
Bonjour, monde!
Bonjour, monde!

Mes questions suivies:

1)

.type writeMe, @function 

Qu'est-ce que ce code signifie? Information pour "GCC"? Qu'est ce que ça fait? Est-ce que je dois faire ça?

2)

Dois-je écrire cette op délation. si la fonction a été déclarée dans le fichier C?

.type _main, @function 

_main est déclaré dans le fichier C, dois-je écrire?

3)

popl (__eip)    #; pop return location 
popl %ecx     #; pop first argument, msg 
popl %edx     #; pop second argument, len 
........ 
pushl (__eip)    #; push return location 

Je l'ai utilisé ce code dans writeMe, est-il sûr? En d'autres termes, puis-je afficher des arguments, ou GCC va-t-il l'afficher automatiquement?

popl %ecx    #; pop return location 
popl %ecx    #; pop first argument, msg 
popl %edx    #; pop second argument, len 
.... 
subl $0x0C, %esp  #; restore stack 

J'ai utilisé ce code en seconde fonction. Je vous demande, lequel est sûr et correct?

4) Ai-je besoin de restaurer les registres après avoir appelé la fonction d'assemblage de C? (J'ai entendu que je dois restaurer l'EDI mais qu'en est-il des autres?)

Merci pour toutes vos réponses.

+0

Il existe quelques liens utiles sur http://stackoverflow.com/tags/x86/info. esp: comment utiliser un débogueur sur votre code asm, et des liens vers des guides/tutoriels. –

Répondre

3

1) Définit le type du symbole à utiliser. Ce n'est pas nécessaire, sauf dans des cas spéciaux, par exemple des bibliothèques partagées.

2) Non, cela a été fait par le compilateur pour les fonctions définies dans C.

3) Ces deux ont tort. Vous devez accéder aux arguments relatifs à esp ou, après avoir configuré un cadre de pile standard, par rapport à ebp.

4) Vous devriez lire la documentation ABI appropriée pour plus d'informations sur la convention d'appel. Généralement, vous pouvez utiliser eax, ecx et edx le reste doit être conservé.