问题
让我们考虑一下:
int main(){
write(1, "hello", 5);
return 0;
}
我正在读一本书,建议上面代码的汇编输出应该是:
main:
mov $4, %eax
mov $1 %ebx
mov %string, %ecx
mov $len, %edx
int $0x80
(上面的代码是用32位架构编译的。通过寄存器传递参数不是由'64位约定通过寄存器传递参数引起的,但它是由事实引起的,我们进行了系统调用。)
我的64位Ubuntu机器上的输出:gcc -S main.c -m32
是:
pushl $4
pushl $string
pushl $1
call write
我的疑惑
所以它让我很困惑。为什么gcc将其编译为“正常”调用,而不是作为系统调用。 在这种情况下,使处理器使用内核函数(如write)的方法是什么?
答案 0 :(得分:4)
我正在读一本书,建议上面代码的汇编输出应该是......
你不应该相信你读到的一切: - )
没有要求将C代码转换为特定的汇编代码,C标准要求的唯一要求是生成的代码以某种方式运行。
是否通过直接使用int $80
(或sysenter
)调用OS系统调用来完成,或者是否通过调用库例程write()
来完成最终以类似的方式调用操作系统,这在很大程度上是无关紧要的。
如果您要查找和反汇编write()
代码,您可能会发现它只是将堆栈中的值读取到寄存器中,然后以与您显示的代码相同的方式调用操作系统int $80
。
顺便说一下,如果您想将gcc
移植到使用call 5
进行操作系统级系统调用的完全不同的架构,该怎么办?如果gcc
正在将特定的int $80
调用注入到程序集流中,那么这将无法正常工作。
但是,如果它正在向write()
函数注入一个调用,那么您所要做的就是确保将它与包含已修改write()
函数的正确库链接({{1}而不是call 5
)。