赞
踩
双口ram存储器
当您运行任何C程序时,其可执行映像都会以有组织的方式加载到计算机的RAM中,这称为C程序的进程地址空间或内存布局。 在这里,我试图分两部分向您展示同一件事。
/!\:最初发布于www.vishalchovatiya.com 。
在第1部分(即“概述”)中,我们将看到逐段概述;在第2部分(即“示例”)中,我们将看到C程序如何存储在RAM存储器中? 举个例子。
第1部分:概述
C程序的内存布局以下列方式组织:
注意:不仅仅是这4个部分,还有很多,但是这4个部分是了解C程序在机器级别上工作的核心。
- HIGHER ADDRESS
- +------------------------+
- | Unmapped or reserved | Command-line argument & Environment variables
- |------------------------|------------------------
- | Stack segment | |
- | | | | Stack frame
- | v | v
- | |
- | ^ | ^
- | | | | Dynamic memory
- | Heap segment | |
- |------------------------|------------------------
- | Uninitialized data |
- |------------------------| Data segment
- | Initialized data |
- |------------------------|------------------------
- | |
- | Text segment | Executable code
- | |
- +------------------------+
- LOWER ADDRESS
main()
也是),包括用户定义的函数和系统函数。 本部分有两个小节
1.初始化数据
char string[ ] = "hello world"
定义的全局字符串以及在main
(即global)之外的int count=1
类的语句将存储在初始化的读写区域中。 const int A=3
这样的全局语句; 使变量A
只读,并存储在初始化的只读区域中。 2.未初始化的数据(BSS段)
int A
的全局变量将存储在未初始化的数据段中。 诸如static int X=0
类的语句也将存储在此段中,因为它初始化为零。 /lib/ld-linux.so.2
)。 malloc()
, calloc()
, realloc()
和C ++的new
分配)驻留的区域。 free()
或delete
)。 释放的内存返回到堆,但不必返回到操作系统(根本不必返回),因此无序malloc
/ free
最终会导致堆碎片。 您可以在此处了解有关malloc的更多信息。 main()
中声明的所有那些变量。 我在这里写了一篇关于函数堆栈框架的详细文章。 第2部分:示例
我们已经举了一个简单的例子,如标题以及其内存布局所示。 正如我们在上一部分(即概述)中所讨论的,程序的可执行映像如何划分为不同的段并存储在内存(RAM)中。 现在,我们通过使用上面提供的示例代码来理解这些块。
装载机
- $ readelf --segments ./a.out
- Elf file type is EXEC (Executable file)
- Entry point 0x8048300
- There are 9 program headers, starting at offset 52
- Program Headers:
- Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
- PHDR 0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
- INTERP 0x000154 0x08048154 0x08048154 0x00013 0x00013 R 0x1
- [Requesting program interpreter: /lib/ld-linux.so.2]
- LOAD 0x000000 0x08048000 0x08048000 0x00608 0x00608 R E 0x1000
- LOAD 0x000f08 0x08049f08 0x08049f08 0x00118 0x00124 RW 0x1000
- DYNAMIC 0x000f14 0x08049f14 0x08049f14 0x000e8 0x000e8 RW 0x4
- NOTE 0x000168 0x08048168 0x08048168 0x00020 0x00020 R 0x4
- GNU_EH_FRAME 0x0004c4 0x080484c4 0x080484c4 0x00044 0x00044 R 0x4
- GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10
- GNU_RELRO 0x000f08 0x08049f08 0x08049f08 0x000f8 0x000f8 R 0x1
- Section to Segment mapping:
- Segment Sections...
- 00
- 01 .interp
- 02 .interp .note.ABI-tag .hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame
- 03 .init_array .fini_array .jcr .dynamic .got .got.plt .data .bss
- 04 .dynamic
- 05 .note.ABI-tag
- 06 .eh_frame_hdr
- 07
- 08 .init_array .fini_array .jcr .dynamic .got
.data
, .bss
, .text
等段。 但是堆栈段未显示为在运行时创建的,而是由OS(精确地是loader和kernel)决定的。 INTERP
定义了加载器的名称和路径,该加载器将通过读取这些段将当前的二进制映像加载到RAM中。 这是/lib/ld-linux.so.2.
编译C代码时,您将获得可执行映像(可以是.bin
, .exe
, .hex
, .out
或任何扩展名等任何形式)。 该可执行文件包含Binutils命令$ objdump -d <binary_name>
看到的文本段,如下所示:
- .....
- 080483f1 <main>:
- 80483f1: 8d 4c 24 04 lea 0x4(%esp),%ecx
- 80483f5: 83 e4 f0 and $0xfffffff0,%esp
- 80483f8: ff 71 fc pushl -0x4(%ecx)
- .....
这是可执行的指令,以只读段的形式存储在文本段中,并在需要时由进程共享。 CPU使用程序计数器和执行时在堆栈中创建的堆栈帧读取这些指令。 程序计数器指向要执行的指令的地址,该地址位于文本段中。
初始化数据段
const int x = 1
; 存储在只读区域中。 因此,您不能意外修改它。 char str[] = "Hi!";
& static int var = 0;
存储在读写区域中,因为我们没有使用像const这样的关键字,它使变量为只读。 未初始化的数据段
int i
声明为global的int i
会进入该存储区域,因为默认情况下它没有初始化或初始化为零。 malloc()
, calloc()
等函数来接近OS。 malloc()
函数分配1字节动态内存,并将其地址存储在指针ptr
以跟踪该内存或对其进行访问。 ptr
是main的局部变量,因此它位于main的堆栈框架中,但是它指向的内存在我用*ptr
显示的堆中。 main()
,它也是一个函数,因此,在执行时会为其创建堆栈框架。 尽管在这里我已经讨论了main之前调用的许多函数。 main()
堆栈框架是在函数func()
嵌套之前创建的。 func( )
执行覆盖其局部变量a,并且其堆栈帧将被破坏(在这里倒带是一个精确的词), main()
函数也是如此。 直观的常见问题解答
问:如何确定堆栈的生长方向?
答:简单...! 通过比较两个不同函数的局部变量的地址。
- int *main_ptr = NULL ;
- int *func_ptr = NULL ;
- void func () { int a; func_ptr = &a; }
- int main ()
- {
- int a; main_ptr = &a;
- func();
- (main_ptr > func_ptr) ? printf ( "DOWN\n" ) : printf ( "UP\n" );
- return 0 ;
- }
问:如何故意破坏堆栈?
答:损坏存储在堆栈帧中的SFR值。
- void func ()
- {
- int a;
- memset (&a, 0 , 100 ); // Corrupt SFR values stored in stack frame
- }
- int main ()
- {
- func();
- return 0 ;
- }
问:如何增加堆栈框架大小?
答: alloca()是答案。 GOOGLE一下,或看看这个 。
双口ram存储器
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。