这是简短的控制台应用程序示例
static char buffer[4096]; int main() { for(int i=0;i<4096;i++) { buffer[i] = 1234; } return 0; }
据我所知,由编译器产生的'exe'文件应该包含.bss节来存储'buffer'variables。
我正在使用Tiny C编译器,生成的文件不包含任何对.bss的引用。
DOS Header Magic number: 0x5a4d (MZ) Bytes in last page: 144 Pages in file: 3 Relocations: 0 Size of header in paragraphs: 4 Minimum extra paragraphs: 0 Maximum extra paragraphs: 65535 Initial (relative) SS value: 0 Initial SP value: 0xb8 Initial IP value: 0 Initial (relative) CS value: 0 Address of relocation table: 0x40 Overlay number: 0 OEM identifier: 0 OEM information: 0 PE header offset: 0x80 COFF/File header Machine: 0x14c IMAGE_FILE_MACHINE_I386 Number of sections: 2 Date/time stamp: 0 (Thu, 01 Jan 1970 00:00:00 UTC) Symbol Table offset: 0 Number of symbols: 0 Size of optional header: 0xe0 Characteristics: 0x30f IMAGE_FILE_RELOCS_STRIPPED IMAGE_FILE_EXECUTABLE_IMAGE IMAGE_FILE_LINE_NUMS_STRIPPED IMAGE_FILE_LOCAL_SYMS_STRIPPED IMAGE_FILE_32BIT_MACHINE IMAGE_FILE_DEBUG_STRIPPED Optional/Image header Magic number: 0x10b (PE32) Linker major version: 6 Linker minor version: 0 Size of .text section: 0 Size of .data section: 0 Size of .bss section: 0 Entrypoint: 0x1060 Address of .text section: 0x1000 Address of .data section: 0x2000 ImageBase: 0x400000 Alignment of sections: 0x1000 Alignment factor: 0x200 Major version of required OS: 4 Minor version of required OS: 0 Major version of image: 0 Minor version of image: 0 Major version of subsystem: 4 Minor version of subsystem: 0 Size of image: 0x4000 Size of headers: 0x200 Checksum: 0x95d5 Subsystem required: 0x3 (IMAGE_SUBSYSTEM_WINDOWS_CUI) DLL characteristics: 0 Size of stack to reserve: 0x100000 Size of stack to commit: 0x1000 Size of heap space to reserve: 0x100000 Size of heap space to commit: 0x1000 Data directories IMAGE_DIRECTORY_ENTRY_IMPORT: 0x2000 (40 bytes) IMAGE_DIRECTORY_ENTRY_IAT: 0x2028 (32 bytes) Imported functions msvcrt.dll _controlfp __set_app_type __getmainargs exit _XcptFilter _exit _except_handler3 export directory not found Sections Name: .text Virtual Address: 0x1000 Physical Address: 0x1e8 Size: 0x200 (512 bytes) Pointer To Data: 0x200 Relocations: 0 Characteristics: 0x60000020 IMAGE_SCN_CNT_CODE IMAGE_SCN_MEM_EXECUTE IMAGE_SCN_MEM_READ Name: .data Virtual Address: 0x2000 Physical Address: 0x10e0 Size: 0x200 (512 bytes) Pointer To Data: 0x400 Relocations: 0 Characteristics: 0xc0000040 IMAGE_SCN_CNT_INITIALIZED_DATA IMAGE_SCN_MEM_READ IMAGE_SCN_MEM_WRITE
反汇编的可执行引用“缓冲区”variables的版本,就好像它位于.data节之后。 怎么运行的 ? 数据加载器如何知道应该在.data节后保留特定区域?
可执行文件: https : //www.dropbox.com/s/99bpil11j7396ej/test-bss.exe? dl = 0
PEDUMP在线: http ://pedump.me/40c40172cf08c89c3d97bd6840dbd3a0/
现在知道.data节的内存和磁盘大小,我认为可以解释buffer
的位置以及如何到达那里。
为了保持一致性,我使用了Microsoft Portable Executable和Common Object File Format Specification中的术语。
所以这就是我们所知道的.data部分,它的VirtualSize是4320(0x10E0),SizeOfRawData是512(0x200)。 这意味着磁盘上的.data节512个字节,但在内存中填充为零,大小为4320字节。 SizeOfRawData值是可执行文件中已初始化数据的大小,当您从VirtualSize中减去该值时,将得到未初始化数据的大小。 如注释中所述,这意味着.data节有3808字节的未初始化的数据,这是没有足够的空间来包含4096字节的数组名为buffer
。
那么buffer
在哪里? 它必须从.data部分的初始化部分开始,并继续进入未初始化的部分。 PECOFF要求将SizeOfRawData值四舍五入到FileAlignment(512)的下一个倍数。 这意味着,当链接器创建可执行文件的.data节时,它会用未初始化的数据填充磁盘上的初始化数据,以便SizeOfRawData最终为512的倍数。换句话说,可执行文件中的初始化数据的实际数量小于512字节和未初始化数据的实际数量大于3808。
此图尝试显示链接器如何布置.data部分。 上半部分表示内存中相对于.data节开头的地方,链接器放置可执行文件中使用的所有初始化变量和未初始化变量。 中间的部分显示了放置buffer
位置。 底部显示了作为可执行文件中的初始化数据存在的.data部分的一部分。
+------------------+----------------------------------------+ | Initialized Vars | Uninitialized Variables | +--------------------+-----------------------------------+--+ | | buffer[4096] | | +--------------------+---+-------------------------------+--+ | Initialized on Disk | 4320 +------------------------+ 0 512
没有必要在exe文件中存储BSS部分,因为它只包含未初始化的数据。 它是由启动代码分配的,也就是在进入main之前执行的代码。 BSS部分通常在RAM的DATA部分之后分配,并且通过启动代码正常(不总是)清零。 相反,DATA部分是初始化的(带有在源文件中指定的值),所以它必须存储在exe文件映像中。