一: 实例源码
printf 实现原理:
printf 函数肯定有一个格式串,例子中为
"string = %s xx = %s , hex = %d \n",printf的实现是依据该格式串,智能的解析
% 后面的字符,假如第一个% 后面是s 代表格式串后面的第一个参数代表一个地址,如果是d则代表是一个十进制。 以此类推。
所以要特别注意格式串的编写,如果多写了(printf("%s %s %s \n",p1,p2), 少了p3 , 那么解析到第三个%的时候会自动去相应的栈取一个数当做
是一个指针,这时候就很可能内存错误等)
#include <stdio.h>
int sum()
{
char * p = "ttttt \n";
printf("string = %s xx = %s , hex = %d \n","haha",p,5);
return 0;
}
二: 生成汇编
gcc -O2 -s test.c 得到test.s
如图:
我们可以获得下面信息:
1) .string : 因为 "ttttt \n" 是放在只读数据区(在ELF 中对应.rodata),所以可以推断出
"string = %s xx = %s , hex = %d \n" 这个字符串也是放在只读数据区。
2)具体的汇编代码解释如下
push1 %ebp :保存旧的ebp 的内容
mov1 %esp %ebp : 保存新的ebp
$.LC0, 8(%esp) :将.LC0 对应的地址放到栈中
xorl %eax %eax :%eax 是专门保存函数的返回值的,因为在sum 中是return 0 ,对任-的
y, y^y = 0
sum 函数帧栈分布如下图:
-----------
| 0:old %ebp <-- %ebp
-------------
|-4:
------------
|-8:
------------
|-12: 5
------------
|-16: "ttttt \n" 地址
------------
|-20: "haha" 地址
------------
|-24: "string = %s xx = %s , hex = %d \n" 地址 <-- %esp
------------
|
------------
参考资料: 《深入理解计算机系统》 第三章, 第七章ELF部分