变量访问
全局变量和局部变量
局部静态变量位置:
rip作偏移 05ae+0a92=1040
64位系统
6 static int a=0;
7 a++;
0x00000000004005a8 <+11>: mov 0x200a92(%rip),%eax # 0x601040 <_ZZ4testiE1a>
0x00000000004005ae <+17>: add $0x1,%eax
0x00000000004005b1 <+20>: mov %eax,0x200a89(%rip) # 0x601040 <_ZZ4testiE1a>
x /16x 0x601040
0x601040 <_ZZ4testiE1a>: 0x00000001
局部静态变量初始化:
static int a=0; //不在栈中初始化
static int a=变量; //栈中初始化,存储在栈外
64位系统实例
6 static int a=n;
0x0000000000400688 <+11>: mov $0x601058,%eax //标记位地址在0x601060前2个字节
0x000000000040068d <+16>: movzbl (%rax),%eax //movzbl “零扩展”
//|63..32|31..16|15-8|7-0| rax eax ax ah al 关系
// |AH.|AL.|
// |AX.....|
// |EAX............|
//|RAX...................|
0x0000000000400690 <+19>: test %al,%al //执行AND逻辑操作,设置标志寄存器 C,O,P,Z,S。
//ZF:运算结果为0,zf为1
0x0000000000400692 <+21>: jne 0x4006ba <test(int)+61> //当ZF=0,转至标号处执行
0x0000000000400694 <+23>: mov $0x601058,%edi
0x0000000000400699 <+28>: callq 0x400540 <__cxa_guard_acquire@plt> //线程安全锁
0x000000000040069e <+33>: test %eax,%eax
0x00000000004006a0 <+35>: setne %al //SETE取标志寄存器中ZF的值, 放到AL中. SETNE取得ZF值后, 取反, 再放到AL中.
0x00000000004006a3 <+38>: test %al,%al //??
0x00000000004006a5 <+40>: je 0x4006ba <test(int)+61>
0x00000000004006a7 <+42>: mov -0x4(%rbp),%eax
0x00000000004006aa <+45>: mov %eax,0x2009b0(%rip) //初始化 # 0x601060 <_ZZ4testiE1a>
0x00000000004006b0 <+51>: mov $0x601058,%edi
0x00000000004006b5 <+56>: callq 0x400580 <__cxa_guard_release@plt>
7 a++;
0x00000000004006ba <+61>: mov 0x2009a0(%rip),%eax # 0x601060 <_ZZ4testiE1a>
0x00000000004006c0 <+67>: add $0x1,%eax
0x00000000004006c3 <+70>: mov %eax,0x200997(%rip) # 0x601060 <_ZZ4testiE1a>
堆变量
%rax存了地址 ,(%rax) 解引用
6 int *pnew =new(int);
0x0000000000400668 <+11>: mov $0x4,%edi
0x000000000040066d <+16>: callq 0x400560 <_Znwm@plt> //new <malloc@plt>shi malloc
0x0000000000400672 <+21>: mov %rax,-0x8(%rbp)
7 (*pnew)+=1;
0x0000000000400676 <+25>: mov -0x8(%rbp),%rax //pnew地址
0x000000000040067a <+29>: mov (%rax),%eax //pnew地址存的值
0x000000000040067c <+31>: lea 0x1(%rax),%edx //把rax寄存器的数+0x1 传送到 edx寄存器中
0x000000000040067f <+34>: mov -0x8(%rbp),%rax
0x0000000000400683 <+38>: mov %edx,(%rax) //edx为计算结果,放回地址-0x8(%rbp)
函数指针
%rax存了地址 callq *%rax跳转
...................
12 int(*p)(int);
13 p=fun;
0x00000000004005b8 <+11>: movq $0x40059d,-0x8(%rbp) 地址立即数
14 return p(n);
0x00000000004005c0 <+19>: mov -0x14(%rbp),%edx
0x00000000004005c3 <+22>: mov -0x8(%rbp),%rax
0x00000000004005c7 <+26>: mov %edx,%edi
0x00000000004005c9 <+28>: callq *%rax
.................
Dump of assembler code for function fun(int):
5 {
0x000000000040059d <+0>: push %rbp
................
对齐规则
对齐规则参考
自身对齐值:数据类型本身的对齐值,例如char类型的自身对齐值是1,short类型是2;
指定对齐值:编译器或程序员指定的对齐值,32位单片机的指定对齐值默认是4;
有效对齐值:自身对齐值和指定对齐值中较小的那个。
对齐有两个规则:
1、不但结构体的成员有有效对齐值,结构体本身也有对齐值,这主要是考虑结构体的数组,对于结构体或者类,要将其补齐为其有效对齐值的整数倍。结构体的有效对齐值是其最大数据成员的自身对齐值;
2、存放成员的起始地址必须是该成员有效对齐值的整数倍。
存储位置
3G
0xbfaa 5060 栈地址 2.xG
0x09b3 e008 堆地址
0x0804 84f1 代码段
0x0804 98a4 全局数据 128M多
0G
局部变量存储顺序/参数入栈顺序
栈底 往上 sp方向
高地址 往 低地址
后定义的变量 再 先定义的
简单的结构 再 复杂的结构
32位系统实例
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct dd
{
double e;
double f;
};
struct complexst
{
char a;
double b;
char c;
char d;
struct dd d1;
};
unsigned int ga=305419896;
#define wrq "wrq"
int fun()
{
int b=-5;
char *gp=(char*)&ga;
gp++;
*gp=0;
float f=1.5;
int c=2147483648; //0x7FFFFFFF+1;
const char a[15]={"abcdefgh"};
char *hp=(char*)new(int);
*hp='x';
(*hp)++;
*hp='y';
char a2dem[][4]={{'a','b'},{"cde"}};
a2dem[1][1]='x';
struct complexst com1;
com1.a=1;
com1.b=2;
com1.c=3;
com1.d=4;
com1.d1.e=5;
com1.d1.f=5;
abort();
return 0;
}
int main(int argc, char** argv)
{
fun();
}