程序内存布局

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Linux内核的通用链表函数库
Linux内核的通用链表函数库
list_for_each
#define list_for_each(pos, head) \ for (pos = (head)->next; pos != (head); pos = pos->next)
16
list_for_each_entry
静态布局和运行时布局的对应
系统栈与过程调用
栈顶
…. 局部变量 var_B2
局部变量 var_B1 其他信息 返回地址 参数 arg_B1=4 参数 arg_B2=3 局部变量 var_A2 局部变量 var_A1
func_B 的栈帧
func_A 的栈帧
其他信息
返回地址 参数arg_A1= 2 参数 arg_A2 = 1 局部变量 var_main
保存上层函数的 栈帧EBP
为局部变量分配空间
回收局部变量占 用的空间
参数y = 5 参数x = g 返回地址
EBP
地址高端
上层函数的栈帧EBP 局部变量a 局部变量b
注:图中每个格都表示4个字节 地址低端
ESP
一个小结论: 函数的参数都在EBP所指示的内存地址的正偏移处,函数内部 的局部变量都在EBP所指示的内存地址的负偏移处。
关键字volatile的作用
C程序中如何内嵌汇编语言(gcc)
__asm__(".align 2\n\t" "movl %eax, %ebx\n\t" "test %ebx, %ecx\n\t" "jne error\n\t" "sti\n\t" "error: popl %edi\n\t" "subl %ecx, %ebx"); __asm__ __volatile__( …..); 简单吗?No!
push operand pop operand call Label call operand ret sub ESP, 1 ; mov [ESP], operand ; mov operand, [ESP] ; add ESP, 1 ; push EIP ; jmp Label ; push EIP ; jmp operand; pop EIP ;
侯捷(译). 《深度探索C++对象模型》
Linux的虚拟内存管理
Linux的虚拟内存管理机制为应用程序和驱动 程序 提供了两种服务: 使每个进程都拥有自己独立的内存地址空间;对 于32位Linux而言,每个任务可寻址的内存地址空 间都为0x00000000 ~ 0xFFFFFFFF(232, 4GB)
关于静态数据区
C程序1: int a; int b = 5; int c; int d = 6; int e; int main() …. C程序2: int a; int c; int b = 5; int d = 6; int e[100]; int main() ….
思考:(1) 程序1中a 、b、c等全局变量的地址在运行期间是 否会改变? (2)程序1中a 、b、c等全局变量在内存中是连续存放的吗? (3) 两个程序分别生成的两个可执行文件哪个更大?
当物理内存不够4GB时,虚拟内存管理模块会用外 存空间模拟内存空间,并且该模拟过程对应用程序 是透明的。
23
用户地址空间与内核地址空间
1. Linux将每个进程的4GB的独立地址空间又划分为用 户地址空间(0x00000000 ~ 0xBFFFFFFF)和 内核 地址空间(0xC0000000 ~ 0xFFFFFFFF)两部分。 2. 操作系统内核代码和数据存放在内核地址空间;每 个进程自己私有的代码和数据存放在用户地址空间
如何在栈上动态分配内存?
有错吗?
有问题吗?
有问题吗?
C与汇编的混合编程(MVC)
函数返回值怎么传递给调用者?
1. 如果返回值小于等于4个字节,则用EAX寄存器返 回。 2. 如果返回值介于4到8个字节之间,则用EAX和 EDX两个寄存器返回。 3. 如果返回值超过8个字节,则:
– – – – 在调用者的栈帧中开辟一块临时空间,其大小刚好等于 返回值对象。(生成一个临时对象) 将临时对象地址作为一个隐含的参数通过栈传递给函数 函数将运算结果拷贝到临时对象,并将临时对象地址用 EAX传递给调用者 调用者再将临时对象拷贝给非临时对象。
变量的生存期
把程序运行时一个变量占有内存空间的时间段称为该变量的 生存期。C++把变量的生存期分为:静态、自动和动态三种。 静态生存期:全局变量都具有静态生存期,它们的内存空间从 程序开始执行时就进行分配,直到程序结束才被收回。 自动生存期:局部变量和函数形参一般都具有自动生存期,它 们的内存空间在程序执行到定义它们的复合语句(包括函数体) 时才分配,当定义它们的复合语句执行结束时内存被收回。 动态生存期:具有动态生存期的变量的生存时间是由程序员自 由控制的,其内存空间用new操作符分配,用delete回收。 在定义局部变量时,可以为它们加上存储类修饰符auto、static 和register来指出它们的生存期。 定义为static存储类型的局部变量具有静态生存期,它们也被 存放在静态数据区。
——自己动手写操作系统
5Fra Baidu bibliotek
浮点数的内存表示问题
结构体变量的内存表示
gcc中怎么控制内存对齐
struct A { … } __attribute__((packed)); struct B { … } __attribute__((aligned (8)));
#pragma pack(n) //n的取值可以为1、2、4、8 #pragma pack() // 取消对齐,按照编译器的默认对齐方式对齐 编译器的编译选项??
为什么C语言不支持这样的语法?
输出什么? ①
Version 1.0
输出什么? ②
输出什么? ③
如何攻破密码验证程序?
程序“飞了”
程序又“飞了”
程序“飞”到哪儿了?
关于缓冲区溢出攻击
请参阅论文: 《Smashing The Stack For Fun And Profit 》
有安全漏洞的程序
怎么利用C实现一套通用链表函数库?
不怎么通用的方式:
Linux内核的通用链表函数库
Linux内核的通用链表函数库
Linux内核的通用链表函数库
#define offsetof(s,m) (size_t)&(((s *)0)->m) #define LIST_HEAD_INIT(name) { &(name), &(name) } #define LIST_HEAD(name) \ struct list_head name = LIST_HEAD_INIT(name)
3. 不同的节被装载到运行时虚拟地址空间不同的区 域(VMA),不同的VMA为赋予不同的属性:
– 可读、可写、可执行
下面程序中的变量都放到哪个节了?
int g1 = 84; int g2; const int g3 = 100; char *str = “Hello!”; void f1(int i) { printf(“%d\n”, i); } int main() { static int var1 = 85; static int var2; int a = 1; int b; char *p = (char*)malloc(1000); f(a+b); return 0; }
main 的栈帧
栈底
….
CPU对过程调用的支持
相关的寄存器: 1. ESP:存放一个指针,该指针指向系统栈最上面一个栈帧的 栈顶,即整个系统栈的栈顶。 2. EBP:存放一个指针,该指针指向系统栈最上面一个栈帧的 栈底,即当前栈帧的栈底。有时也被称为栈帧寄存器。 3. EIP:指令寄存器,存放一个指针,指向下一条等待执行的 指令地址。 相关的机器指令:
汇编语言中怎么访问结构体变量
AT&T汇编中最复杂的寻址方式: segreg: disp(base, index, scale) 例子: struct test { int a; int b; } struct test bar[10]; movl ds:4(bar, 5, 8), %eax 等价于 eax = bar[5].b;
输出什么?
存储位置是否相同?
C程序的静态布局(ELF文件结构)
1. Linux中的可执行文件遵循ELF文件格式规范 2. ELF文件中包含很多“节”(section)
– – – – – .code 或 .text节:编译之后的机器代码 .data节:已初始化的全局变量和静态局部变量 .bss节:未初始化的全局变量和静态局部变量 .rodata节:程序中的常量 …
3. 虽然Linux的内核代码和数据被映射到了每个进程的 地址空间中(所有进程看到的内容是相同的),但 在实际的物理内存中,只有内核代码和数据的一份 拷贝。
4. 随着进程的切换,当前有效的用户地址空间也在切 换。
24
用户地址空间与内核地址空间
25
C程序运行时内存布局(进程地址空间布局)
全局变量、用static修饰的局部变量都存储在静态数据区。 程序指令和大部分字面常量都存储在代码区。 大部分函数的形参和局部变量都存储在栈区。 程序中动态分配的内存都存储在堆区。 一小部分函数形参和局部变量存储在CPU寄存器组中。 栈区
Linux内核分析 之
程序的内存布局
Version 1.0
本讲知识点
一般问题:内存对齐、大小端 C语言中各种变量类型的内存布局 进程的静态布局与运行时布局
C程序中的代码、变量是怎么放置的?(静态、运行时) 代码区、数据区、栈区、堆区 函数调用与栈、调用规范
Linux内核对进程地址空间的管理
…(动态库映射区)
堆区 静态数据区 已初始化区 未初始化区 CPU寄存器组
常量数据区
代码区
代码区?数据区?
main函数为空居然也有输出?
/* test.cpp */ /* 编译:g++ test.cpp –o init */
main是最先执行的函数吗?
#include <stdio.h> static __attribute__((constructor)) void before(){ printf("Hello"); } static __attribute__((destructor)) void after() { printf(" World!\n"); } int main(int args, char ** argv) { return 0; }
主要参考书目
• 程序员的自我修养 • 俞甲子 石凡 潘爱民 • 电子工业出版社
主要参考书目
• 高级C/C++编译技术 • (美)米兰· 斯特瓦诺维奇 (Milan Stevanovic) • 机械工业出版社
名言
真正了不起的程序员对自己的程序 的每一个字节都了如指掌。
——程序员的自我修养
在你立足处深挖下去, 就会有泉水涌出! 别管蒙昧者们叫嚷: “下面永远是地狱!”
#define list_for_each_entry(pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \ pos = list_entry(pos->member.next, typeof(*pos), member))
17
联合类型变量的内存表示
联合类型的用途
1. 创建变色龙类型: struct Variant { char type; union { int iVal; long lVal; float fVal; … } 2. 超级强制类型转换
位域
应用位域的例子—段描述符
C++中的对象在内存中如何表示?
main执行完后程序结束了吗?
/* int atexit (void (*)(void)); */ #include <stdio.h> #include <stdlib.h> void f(void) { printf(―Bye! World!\n‖); } int main(int args, char ** argv) { atexit(f); return 0; }
相关文档
最新文档