为什么这个 assemble 代码会出现 Segmentation Fault?
Why this assemble code occur Segmentation Fault?
为什么这段代码给出段错误?
(它由 Intel Assemble 语法编码)
结果是这样的
return value : 80
[Dump]
eax : 0x00000012
ebx : 0x00000004
ecx : 0x00000400
edx : 0x4010a980
Segmentation fault (core dumped)
我想我有足够的代码来防止分段错误。
每个函数都有序言和结尾来维护堆栈内存。
但是,出现了Segmentation Fault错误。
[补充说明]
如果我删除代码 '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
If I remove the code 'mov ebx, 4', then segmentation fault error had been removed. (But the result is not fit to my intention)
EBX
寄存器在几乎所有 x86 调用约定中都是被调用者保存的。这意味着叶函数不能破坏它的值。如果它需要使用EBX
,它必须在函数的顶部保存它的原始值并在最后恢复它。这通常通过 PUSH
+POP
指令来完成,以将寄存器的值保存在堆栈上。
您的 pig
函数正在使用 mov ebx, 4
指令破坏 EBX
,但它 没有 注意保存和恢复其原始价值。这违反了调用约定,这很重要,因为您正在与 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
Every function has prologue and epilogue to maintain stack memory.
这真的没有必要。 pig
函数根本不使用堆栈,除了检索参数,因此您可以将其简单地写为:
pig:
mov eax, [esp+4]
mov ecx, 4
mul ecx
ret
通过直接使用堆栈指针 (ESP
),基本指针 (EBP
) 的使用可以类似地从其他函数中删除,即使是那些使用堆栈的函数。这与编译器为释放 EBP
作为附加寄存器并保存 prologue/epilogue 膨胀而进行的优化相同。但是如果你更愿意这样做,那么除了性能之外它不会损害任何东西。
重要的是您要遵循调用约定。 EAX
、EDX
和 ECX
寄存器可以自由破坏叶函数内部;其余的都需要显式保存并恢复为原始值。当您在堆栈上分配 space 时,您需要确保释放它。你这样做的方式是灵活的,无论是 sub esp, xx
…add esp, xx
还是你的序言......结尾。
为什么这段代码给出段错误? (它由 Intel Assemble 语法编码)
结果是这样的
return value : 80
[Dump]
eax : 0x00000012
ebx : 0x00000004
ecx : 0x00000400
edx : 0x4010a980
Segmentation fault (core dumped)
我想我有足够的代码来防止分段错误。 每个函数都有序言和结尾来维护堆栈内存。
但是,出现了Segmentation Fault错误。
[补充说明] 如果我删除代码 '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
If I remove the code 'mov ebx, 4', then segmentation fault error had been removed. (But the result is not fit to my intention)
EBX
寄存器在几乎所有 x86 调用约定中都是被调用者保存的。这意味着叶函数不能破坏它的值。如果它需要使用EBX
,它必须在函数的顶部保存它的原始值并在最后恢复它。这通常通过 PUSH
+POP
指令来完成,以将寄存器的值保存在堆栈上。
您的 pig
函数正在使用 mov ebx, 4
指令破坏 EBX
,但它 没有 注意保存和恢复其原始价值。这违反了调用约定,这很重要,因为您正在与 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
Every function has prologue and epilogue to maintain stack memory.
这真的没有必要。 pig
函数根本不使用堆栈,除了检索参数,因此您可以将其简单地写为:
pig:
mov eax, [esp+4]
mov ecx, 4
mul ecx
ret
通过直接使用堆栈指针 (ESP
),基本指针 (EBP
) 的使用可以类似地从其他函数中删除,即使是那些使用堆栈的函数。这与编译器为释放 EBP
作为附加寄存器并保存 prologue/epilogue 膨胀而进行的优化相同。但是如果你更愿意这样做,那么除了性能之外它不会损害任何东西。
重要的是您要遵循调用约定。 EAX
、EDX
和 ECX
寄存器可以自由破坏叶函数内部;其余的都需要显式保存并恢复为原始值。当您在堆栈上分配 space 时,您需要确保释放它。你这样做的方式是灵活的,无论是 sub esp, xx
…add esp, xx
还是你的序言......结尾。