【发布时间】:2016-04-03 14:15:01
【问题描述】:
我发现并研究了x86 memory access segmentation fault,但它在我的代码中不起作用。不同之处可能在于我不使用单独的 .text 和 .data 段,而是通过创建自定义 ELF 标头将所有段保存在一个段中。这是否解释了 SYS_BRK 调用失败的原因?
然后程序继续使内存页面读/写/执行等。 我试图找到说明问题的最小代码示例。
在 kdbg 中,示例确实有效,但从命令行启动时无效,因此会打印消息。
cpu 386
bits 32
; System calls used
%assign SYS_EXIT 1
%assign SYS_WRITE 4
%assign SYS_BRK 45
%assign SYS_MPROTECT 125
; flags for SYS_MPROTECT
%assign PROT_READ 1
%assign PROT_WRITE 2
%assign PROT_EXEC 4
%assign STDOUT 1
memstart: org 0x08048000
ehdr: ; Elf32_Ehdr (see https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
db 0x7F, "ELF" ; e_ident[EI_MAG0..EI_MAG03]
db 1 ; e_ident[EI_CLASS]
db 1 ; e_ident[EI_DATA]
db 1 ; e_ident[EI_VERSION]
db 0 ; e_ident[EI_OSABI]
db 0 ; e_ident[EI_ABIVERSION]
times 7 db 0 ; e_ident[EI_PAD]
dw 2 ; e_type
dw 3 ; e_machine
dd 1 ; e_version
dd start ; e_entry
dd phdr - $$ ; e_phoff
dd 0 ; e_shoff
dd 0 ; e_flags
dw ehdrsize ; e_ehsize
dw phdrsize ; e_phentsize
dw 1 ; e_phnum
dw 0 ; e_shentsize
dw 0 ; e_shnum
dw 0 ; e_shstrndx
ehdrsize equ $ - ehdr
phdr: ; Elf32_Phdr
dd 1 ; p_type
dd 0 ; p_offset
dd $$ ; p_vaddr
dd $$ ; p_paddr
dd filesize ; p_filesz
dd filesize ; p_memsz
dd 5 ; p_flags
dd 0x1000 ; p_align
phdrsize equ $ - phdr
memsize: dd 16*4096 ; = 16 * 4K pages
memtop: dd 0
start: ;int 3
xor ebx, ebx ; find the amount of allocated memory
mov eax, SYS_BRK
int 0x80 ; eax contains current memtop
sub eax, memstart ; got enough memory?
test eax, [memsize]
ja memgood
mov eax, memstart ; raise memory limit to memstart + memsize
add eax, [memsize]
mov ebx, eax
mov ecx, eax ; save requested memory size in ecx
mov eax, SYS_BRK
int 0x80
cmp eax, ecx
jne brk_error ; raising memory limit failed
memgood: mov edx, (PROT_READ | PROT_WRITE | PROT_EXEC)
mov ecx, [memsize] ; make memory read/write/execute
mov ebx, memstart
mov eax, SYS_MPROTECT
int 0x80
test eax, eax
js bailout
jmp launch ; lets start the party
brk_error: mov edx, brkelen
mov ecx, brke
mov ebx, STDOUT
mov eax, SYS_WRITE
int 0x80
jmp bailout
brke: db 'SYS_BRK failed, bye', 10
brkelen equ $ - brke
bailout: mov eax, SYS_EXIT
xor ebx, ebx
int 0x80
launch: mov edx, succlen
mov ecx, succ
mov ebx, STDOUT
mov eax, SYS_WRITE
int 0x80
jmp bailout
succ: db 'Success with mem config, bye', 10
succlen equ $ - succ
filesize equ $ - $$
【问题讨论】:
-
我看到了您的回答并验证它有效。标头是常规的,只是只有一个段,因此没有代码/数据/bss 分隔。 (哎呀,突然进入帖子)。我编辑了问题以显示完整的初始化,但这并没有什么不同,所以我把这些部分省略了。
-
对不起,(第一次使用)。我的代码的问题是第二次调用 BRK。当我将
int 3放在int 128前面时,我得到了关于调试器断点的预期消息。如果我把它放在程序永远不会到达那里。从控制台运行时,程序似乎只是挂起。 -
我已经删除了我所有的 cmets,因为你现在提供了实际的代码 lol
-
我还没有完全理解你的代码,但是混合代码和数据会导致L1缓存的使用效率低下。 Intel 和 AMD CPU 使用分离的 L1I 和 L1D 高速缓存,因此例如加载
brke字符串将要求高速缓存行位于 L1D 高速缓存中,而周围的代码将要求高速缓存行位于 L1I 高速缓存中。 OTOH,这确实意味着线路在 L2 中很热。此外,您必须通过jmp处理数据,从而降低获取代码的效率。通常你将字符串和其他只读数据放在.rodata中,这会将它们与代码分开,但仍然在.text部分中。
标签: linux assembly system-calls i386 brk