我正在开发一个针对x86和amd64的编译器。我的编译器目前在64位计算机上运行良好。在32位我得到一个段错误。
一个简单的空程序(只有main方法)编译为以下程序集:
extern GC_init
global main
global f_main
segment .data
segment .text
main:
; argc = dword [ebp+8]
; argv = dword [ebp+12]
push edx
; line 3
; proceed GC_init[]
xor dword eax, dword eax
call GC_init
; line 4
; proceed function@main[argc, argv]
push dword [ebp+12]
push dword [ebp+8]
xor dword eax, dword eax
call f_main
sub dword esp, dword 8
pop edx
ret
f_main:
push edx
; line 7
; oax = 0
mov dword eax, dword 0
; line 8
.L0:
pop edx
ret
f_main
是实际的主要方法。 main
只需拨打GC_init
,然后拨打f_main
。
我正在使用以下命令编译和运行代码:
$ nasm -f elf -o test.o test.asm
$ gcc -o etest test.o -lgc
$ ./etest
Segmentation fault (core dumped)
我使用GDB调试程序,发现分段错误来自第二个推送指令(push dword [ebp+12]
)。
以下是有关我的电脑的一些信息:
$ uname -a
Linux [name] 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:30:01 UTC 2014 i686 athlon i686 GNU/Linux
我做错了什么?
答案 0 :(得分:0)
你甚至都没有设置ebp
,这就是你出错的原因。标准函数序言由push ebp; mov ebp, esp
组成。您不必遵循该模式,但如果您没有初始化ebp
,那么您应该访问相对于esp
的参数和本地人(并注意push
更改的事实它)。
此外,要恢复堆栈指针,您需要添加它,而不是减去。这是用sub dword esp, dword 8
替换add dword esp, dword 8
。
main
的可能实现可能如下所示:
sub esp, 12 ; allocate space for edx and 2 outgoing arguments
mov [esp + 8], edx ; save edx
xor eax, eax ; I assume you have a special reason for this
call GC_init
mov eax, [esp + 16]
mov [esp], eax ; copy 1st argument
mov eax, [esp + 20]
mov [esp + 4], eax ; copy 2nd argument
xor eax, eax
call f_main
mov edx, [esp + 8] ; restore edx
add esp, 12 ; restore stack
ret