从helloworld开始
下面的代码是最简单的c语言程序,我们编译成汇编语言看看发生了什么事情。
#include<stdio.h>
int main(){
printf("helloworld");
return 0;
}
.file "a.c"
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
LC0:
.ascii "helloworld\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -4(%ebp)
movl -4(%ebp), %eax
call __alloca
call ___main
movl $LC0, (%esp)
call _printf
movl $0, %eax
leave
ret
.def _printf; .scl 3; .type 32; .endef
虽然汇编语言比较难理解了,但是我们还能看到字符串和函数名等不变的东西。而且我们没有看到关于头文件stdio.h的任何信息,事实上不加#include<stdio.h>
或者前面申明int printf(const char*)
函数的原型也是可以的。由此我们知道了stdio.h也一定只是包含申明函数的东西。
有的人可能发现我的printf申明不对,事实上c语言编译器只进行简单的检查,申明成int printf()
也是可以的,这种声明表示printf接受的参数是不确定的,而不是不接受参数,这与int printf(void)
是不同的。
在汇编语言中我们再也看不到printf返回值是什么,需要传递什么样的参数了。在编译后生成的目标文件中只存在标号这样的东西,因此我们甚至可以欺骗编译器让它认为printf是一个整数。
那么printf是谁实现的呢,printf是包含在c语言标准库中的,你在libstdc.so中找到。