为什么这个汇编代码会发生分段错误?



为什么这段代码会给出分段错误? (它由英特尔汇编语法编码(

结果是这样的。

return value : 80



[Dump]
eax : 0x00000012
ebx : 0x00000004
ecx : 0x00000400
edx : 0x4010a980
Segmentation fault (core dumped)

我想我有足够的代码来防止分段错误。 每个函数都有序幕和尾声来维护堆栈内存。

但是,它会发生分段错误错误。

[补充说明] 如果我删除代码"mov ebx,4",则分段错误已删除。(但结果不符合我的意图(

extern printf
segment .data
dumpmsg db      10,10,10,10,10,10,'[Dump]',10,'eax : 0x%0.8x',10,'ebx : 0x%0.8x',10,'ecx : 0x%0.8x',10,'edx : 0x%0.8x',10,00
msg     db      'return value : %d', 10, 00
segment .bss
segment .text
global  main
main:
push    ebp
mov     ebp,    esp
push    20
call    pig
add     esp,    4
push    eax
push    msg
call    printf
call    print_x
leave
ret
pig:
push    ebp
mov     ebp,    esp
mov     eax,    [ebp+8]
mov     ebx,    4
mul     ebx
leave
ret
print_x:
push    ebp
mov     ebp,    esp
push    edx
push    ecx
push    ebx
push    eax
push    dumpmsg
call    printf
leave
ret

如果我删除代码"mov ebx,4",则分段错误错误已被删除。(但结果不符合我的意图(

EBX寄存器在几乎所有 x86 调用约定中都是被调用方保存的。这意味着叶函数不能破坏其值。如果需要使用EBX,则必须将其原始值保存在函数的顶部,并在末尾恢复。这通常通过PUSH+POP指令来完成,以将寄存器的值保存在堆栈上。

您的pig函数正在破坏EBXmov ebx, 4指令,但它没有注意保存和恢复其原始值。这违反了调用约定,这很重要,因为您正在与 C 代码进行互操作。

修复很简单:

pig:
push    ebp
mov     ebp,    esp
push    ebx
mov     eax,    [ebp+12]
mov     ebx,    4
mul     ebx
pop     ebx
leave
ret

或者,只需使用ECX寄存器来保存除数,因为这个是调用者保存的(因此可以自由删除(:

pig:
push    ebp
mov     ebp,    esp
mov     eax,    [ebp+12]
mov     ecx,    4
mul     ecx
leave
ret

每个函数都有序幕和尾声来维护堆栈内存。

这真的没有必要。pig函数除了检索参数外根本不使用堆栈,因此您可以简单地将其编写为:

pig:
mov     eax,    [esp+4]
mov     ecx,    4
mul     ecx
ret

基指针(EBP(的使用也可以从其他函数中省略,即使是那些使用堆栈的函数,也可以直接使用堆栈指针(ESP(。这与编译器将进行的优化相同,以释放EBP作为附加寄存器并保存序言/尾声膨胀。但是,如果您更愿意这样做,那么除了性能之外,它不会受到任何伤害。

重要的是您遵循调用约定。EAXEDXECX寄存器可以在叶函数内自由切换;其余所有内容都需要显式保存并恢复到其原始值。在堆栈上分配空间时,需要确保释放它。你这样做的方式是灵活的,无论是sub esp, xx...add esp, xx还是序幕...尾声你有。

相关内容

  • 没有找到相关文章

最新更新