在下面的玩具程序中,我在.text部分声明一个变量并写入它,这会产生分段错误,因为.text
部分被标记为READ-ONLY:
Breakpoint 1, 0x00401000 in start ()
(gdb) disassemble
Dump of assembler code for function start:
=> 0x00401000 <+0>: movl $0x2,0x40100a
End of assembler dump.
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
0x00401000 in start ()
(gdb)
以下是objdump
输出:
test.exe: file format pei-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000001f 00401000 00401000 00000200 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .idata 00000014 00402000 00402000 00000400 2**2
CONTENTS, ALLOC, LOAD, DATA
但是,使用--omagic
开关进行链接(禁用READ-ONLY .text
部分)会产生以下结果:
ld --omagic -o test.exe test.obj
test.exe: file format pei-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 0000001f 00401000 00401000 000001d0 2**4
CONTENTS, ALLOC, LOAD, CODE
1 .idata 00000014 00402000 00402000 000003d0 2**2
CONTENTS, ALLOC, LOAD, DATA
但是使用GDB
进行调试会产生以下(奇怪的)结果:
Breakpoint 1, 0x00401000 in start ()
(gdb) disassemble
Dump of assembler code for function start:
=> 0x00401000 <+0>: dec %ebp
0x00401001 <+1>: pop %edx
0x00401002 <+2>: nop
0x00401003 <+3>: add %al,(%ebx)
0x00401005 <+5>: add %al,(%eax)
0x00401007 <+7>: add %al,(%eax,%eax,1)
End of assembler dump.
(gdb) stepi
0x00401001 in start ()
(gdb) stepi
0x00401002 in start ()
(gdb) stepi
0x00401003 in start ()
(gdb) stepi
0x00401005 in start ()
(gdb) stepi
Program received signal SIGSEGV, Segmentation fault.
0x00401005 in start ()
(gdb)
首先,我仍然遇到分段错误,但汇编代码也改变了结构?
如何将.text
部分与Windows 10 x64
上的可写内容相关联?
玩具计划:
BITS 32
section .text
global _start
_start:
mov [var], dword 2
var: dd 0
ret
答案 0 :(得分:3)
--omagic
标志导致GNU链接器生成错误的PECOFF可执行文件。段必须在文件中对齐,文件对齐最小为512字节,但链接器将.text
段放在文件偏移量0x1d0处。
不使用--omagic
标志,而是正常生成可执行文件,然后使用objcopy
更改节标题中的标记:
ld -o test-tmp.exe test.obj
$(OBJCOPY) --set-section-flags .text=code,data,alloc,contents,load test-tmp.exe test.exe
答案 1 :(得分:2)
出于某种原因,ld
完全更改了使用--omagic
选项链接的PE可执行文件。
使用cmp
实用程序快速比较文件显示:
137 177 222
141 0 320
142 6 5
213 0 320
214 2 1
217 142 205
218 154 353
397 0 320
398 2 1
437 0 320
438 4 3
465 0 307
...
有很多差异,虽然ld
原则上只应更改节标题(.text)的节标志,即设置标志IMAGE_SCN_MEM_WRITE
。
使用HxD手动更改标志,即将偏移量为0x19F的字节设置为0xE0可以解决问题......
程序的试运行,互换顺序为var
和ret
(否则程序崩溃):
Breakpoint 1, 0x00401000 in start ()
(gdb) disassemble
Dump of assembler code for function start:
=> 0x00401000 <+0>: movl $0x2,0x40100b
0x0040100a <+10>: ret
End of assembler dump.
(gdb) stepi
0x0040100a in start ()
(gdb) disassemble
Dump of assembler code for function start:
0x00401000 <+0>: movl $0x2,0x40100b
=> 0x0040100a <+10>: ret
End of assembler dump.
(gdb) x/wx var
0x40100b <var>: 0x00000002
(gdb)
我们认为事情按预期发挥作用。
我的结论是ld
以某种方式生成格式错误的PE可执行文件,我看到@RossRidge有这个答案(ld
不尊重各部分的文件对齐)。