【发布时间】:2017-09-08 12:54:58
【问题描述】:
我一直在玩弄ELFIO 库。尤其是One of the examples,它允许人们从头开始创建 ELF 文件——定义节、段、入口点,并为相关节提供二进制内容。
I noticed that a program created this way segfaults when the code segment alignment is chosen less than the page size (0x1000):
// Create a loadable segment
segment* text_seg = writer.segments.add();
text_seg->set_type( PT_LOAD );
text_seg->set_virtual_address( 0x08048000 );
text_seg->set_physical_address( 0x08048000 );
text_seg->set_flags( PF_X | PF_R );
text_seg->set_align( 0x1000 ); // can't change this
注意.text 部分 在同一示例中仅与 0x10 的倍数对齐:
section* text_sec = writer.sections.add( ".text" );
text_sec->set_type( SHT_PROGBITS );
text_sec->set_flags( SHF_ALLOC | SHF_EXECINSTR );
text_sec->set_addr_align( 0x10 );
但是,数据段虽然通过相同的机制单独加载,但不存在这个问题:
segment* data_seg = writer.segments.add();
data_seg->set_type( PT_LOAD );
data_seg->set_virtual_address( 0x08048020 );
data_seg->set_physical_address( 0x08048020 );
data_seg->set_flags( PF_W | PF_R );
data_seg->set_align( 0x10 ); // note here!
现在,在这种特定情况下,数据按设计适合已分配的页面。不确定这是否有任何区别,但我将其虚拟地址更改为 0x8148020,结果仍然可以正常工作。
这是readelf的输出:
Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000001000 0x0000000008048000 0x0000000008048000
0x000000000000001d 0x000000000000001d R E 1000
LOAD 0x0000000000001020 0x0000000008148020 0x0000000008148020
0x000000000000000e 0x000000000000000e RW 10
为什么当可执行段的对齐方式不是0x1000的倍数而数据0x10没有问题时程序执行失败?
更新:不知何故第二次尝试text_seg->set_align( 0x100 ); 也可以,text_seg->set_align( 0x10 ); 失败。页面大小为 0x1000,有趣的是,工作程序的 VirtAddr 在任一段中都没有遵守它:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000100 0x08048100 0x08048100 0x0001d 0x0001d R E 0x100
LOAD 0x000120 0x08148120 0x08148120 0x0000e 0x0000e RW 0x10
SIGSEGV 的一个:
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
LOAD 0x000080 0x08048100 0x08048100 0x0001d 0x0001d R E 0x10
LOAD 0x0000a0 0x08148120 0x08148120 0x0000e 0x0000e RW 0x10
生成的 ELF 为 here。
【问题讨论】:
-
你能发布两个生成的 .ELF 文件吗?
-
@MartinRosenau 当然。我一定犯了一个错误,0x100 也有效。但是 0x10 仍然中断。页面大小为 0x1000。这是两个文件进行比较,还有一些地址调整以使它们更小:(tinyupload.com)
-
如果您需要了解为什么内核的行为与您观察到的一样,您应该深入研究内核源代码。