- 1、本文档共36页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
CC深层探究
1.字节序
int i = 0
char *p = (char*)i;
printf(... %s ...\n,p);
上面的代码在x86下结果是A,但是在其他平台下结果不一定,有可能并不会执行输出。其
原因是在IA32下的字节序是:0X41 00 00 00 ;但是在其他平台下字节序可能会是这
样: 00 00 00 0X41,所以不能保证这样的转换具有正确性。这就是所谓的大端组织和小
端组织。
2.调用栈
void fun(char love,char *p)
{
}
int _tmain(int argc, _TCHAR* argv[])
{
char love = y;
char *p = love you?;
fun(love,p);
return 0;
}
//Gcc callStack.cpp -S
//Cat callStack.s
Asm如下:
.file callStack.c
gcc2_compiled.:
___gnu_compiled_c:
.text
.align 4
.globl _fun //表示函数是全局可见的。
.def _fun; .scl 2; .type 32; .endef
_fun:
pushl %ebp
movl %esp,%ebp
subl $16,%esp
movl 8(%ebp),%eax
movb %al,-1(%ebp)
L1:
movl %ebp,%esp
popl %ebp
ret
.def ___main; .scl 2; .type 32; .endef
LC0:
.ascii love you?\0
.align 4
.globl _main //表示函数是全局可见的。
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp,%ebp
subl $16,%esp
call ___main
movb $121,-1(%ebp)
movl $LC0,-8(%ebp)
movl -8(%ebp),%eax
pushl %eax //参数入栈
movsbl -1(%ebp),%eax
pushl %eax //参数入栈
call _fun //调用fun
addl $8,%esp
xorl %eax,%eax
jmp L2
.p2align 4,,7
L2:
movl %ebp,%esp
popl %ebp
Ret
所以调用函数分为两个步骤:
第一:将参数入栈
第二:将指令执行点转移到函数代码的入口
通常,先压栈的内容存放在高地址区域,后压栈的内容在低地址区域。
需要注意:
1)C语言标准并没有规定参数入栈的顺序,至于从右到左还是从左到右,这由编译器厂
商决定。但是
vc和gcc测试结果表明其都是从右到左。
2)gcc和vc默认的汇编代码是使用ebp寻址的,esp解释了整个函数的栈空间。
3.变量的可见范围和生存周期
void fun()
{
int b = 100;
}
int main()
{
int b = 20;
fun();
return 0;
}
为什么fun里面的b不能访问main的b?这是因为函数在调用之前,编译器不可能知道知道
这个函数的内部变量的准确地址,变量是直到到达函数内部时才通过在栈里面规划出空间从
而宣告自己的真实存在。函数一旦结束,执行点马上返回,esp被重新调整,原来栈里面的
内容就不存在了。也就说这是两个不同的栈,会进行栈的切换。所以一个栈消失后肯定不能
再继续访问。
其次,参数也是调用函数前才放到栈里面,所以函数返回后会消失,所以参数和内部变量有
相同的可见范围。
第三,main调用fun传递了b,并不会导致b的值被改变,因为调用fun的时候是把b的值压
栈,并不是把b的地址压栈,fun并不知道b的地址。
第四,外部变量地址分配:由于外部变量在整个程序运行期间的地址不能改变,所以不可能
放到栈里面,只能是在数据段中。所以这些数据的地址在程序进行链接的时候才能准确得出,
另外该地址从程序开始运行到结束都是固定的,所以任何函数都能存取这些数据。
int global;
void fun()
{
int local = 4;
extern int global2;//由于其定义出现在fun后面,所以必须有一个声明(参见asm
码);
globa
文档评论(0)