c - 关于从 Assembly 调用 C 函数,反之亦然

标签 c assembly x86 calling-convention gnu-assembler

我尝试过从 C 调用 ASM,反之亦然。至少目前它运行完美,但我有疑问。这是我的代码:

test.S 紧随其后:

.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 紧随其后:

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));
}

我的输出与我预期的一样。

Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!

我的问题如下:

1)

.type writeMe, @function

这段代码是什么意思? “GCC”的信息?它有什么作用?我必须这样做吗?

2)

我必须写这个通知操作吗?如果函数在 C 文件中声明?

.type _main, @function

_main 在C 文件中声明,我必须写吗?

3)

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

我在 writeMe 中使用过这段代码,它安全吗?换句话说,我可以弹出参数,还是 GCC 会自动弹出它?

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

我在第二个函数中使用了这段代码。我问你,哪一个是安全正确的?

4) 从 C 调用汇编函数后是否需要恢复寄存器? (我听说我必须恢复 EDI,但其他人呢?)

感谢您的所有回复。

最佳答案

1) 设置函数的符号类型。不需要,除非在特殊情况下,例如共享库。

2) 不,编译器已经为 C 中定义的函数完成了。

3) 这两个都是错误的。您应该访问相对于 esp 的参数,或者在设置标准堆栈框架之后,相对于 ebp

4) 您应该阅读相应的 ABI 文档以获取有关调用约定的信息。通常,您可以使用 eaxecxedx,其余部分必须保留。

关于c - 关于从 Assembly 调用 C 函数,反之亦然,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31464610/

相关文章:

c - 在c中执行汇编代码

assembly - 调用可以是 cdecl 或 stdcall 的函数

debugging - DOS DEBUG 跟踪命令无法按我的预期工作

gdb false 可以重新创建框架的寄存器吗?

assembly - 比较指令无法正常工作

c++ - 实数 - 如何确定是否需要 float 或 double?

c - 尝试在 C 中执行 RPN 时如何修复段错误

gcc - 在标量矩阵加法中使用 vaddss 代替 adds 有什么好处?

c - pthread_create int 而不是 void

c - 在内核编程中激活分页