Assembly 如何使我的程序不崩溃?
我不明白为什么Windows不能在不崩溃的情况下运行这个程序,而且在可执行程序图标上插入了“屏蔽”图标(管理员模式)。这是我的代码(FASM汇编程序,x86-64): 代码对我来说似乎是正确的,我不认为这是问题所在,可能是一些缺少的指令?我不知道 PS:奇怪的效果:当我更改程序的目录(默认在桌面上)时,屏蔽消失了。。。我真的不明白 注:也许对你来说这很明显,但对我来说不是。我的网络搜索没有发现任何结论 [代码编辑1]: 另一个程序的示例,更为简化,无明显原因崩溃:Assembly 如何使我的程序不崩溃?,assembly,fasm,Assembly,Fasm,我不明白为什么Windows不能在不崩溃的情况下运行这个程序,而且在可执行程序图标上插入了“屏蔽”图标(管理员模式)。这是我的代码(FASM汇编程序,x86-64): 代码对我来说似乎是正确的,我不认为这是问题所在,可能是一些缺少的指令?我不知道 PS:奇怪的效果:当我更改程序的目录(默认在桌面上)时,屏蔽消失了。。。我真的不明白 注:也许对你来说这很明显,但对我来说不是。我的网络搜索没有发现任何结论 [代码编辑1]: 另一个程序的示例,更为简化,无明显原因崩溃: format PE conso
format PE console
org 100h
mov ah,09
mov dx,msg
int 21h
mov ah,08
int 21h
int 20h
msg db "hello world!$"
[编辑代码2]:
format PE
entry main
main:
push ebp
mov ebp, esp
mov DWORD [ebp-4], edi
mov DWORD [ebp-16], esi
mov edi, 8
call square
pop ebp
ret
square:
push ebp
mov ebp, esp
mov DWORD [ebp-4], edi
pop ebp
ret
嗯,您正在尝试以两种不同的独立方式设置堆栈帧-通过
enter/leave
和push/pop
。因此,您只是弄乱了堆栈,因此程序在ret
指令上返回了错误的地址
仅使用以下方法之一,不要忘记设置退出代码:
变式1
变式2
这两种变体都不会崩溃,并且会正确终止,尽管它们实际上没有任何用处。你到底想达到什么目的
另外,您的dos示例也可以运行,但您需要使用一些不同的选项来编译它:
format binary as "com"
org 100h
mov ah,09
mov dx,msg
int 21h
mov ah,08
int 21h
int 20h
msg db "hello world!$"
现在在DOS中编译并运行结果.com
文件,或者在Windows或Linux中使用DosBox:
$dosbox myprog.com
猜测一下:您正在交错
leave
和pop
。我猜这会把堆栈搞得一团糟,ret
会失败。@DavidWohlferd:我也想过,但结果是,即使是比这个更简单的程序也会崩溃,甚至不使用leave或enter。发布更简单的代码。这一个也恰好使用了堆栈指针下的内存,这可能是崩溃的原因之一。另外,如果您真的处于64位模式,那么使用32位指针不是最好的主意。不过,我不知道windows将堆栈放在哪里。@Jester:在这里,我编辑了这个问题,使另一个程序出现,它不使用pop/push/LEVE/ret/enter,但仍然崩溃。这可能与格式PE控制台有关吗?
?这是一个使用旧DOS中断的16位代码。难怪会崩溃。问题不是混合拆卸方法,而是重复两次。您可以使用leave
拆下由push ebp
/mov ebp,esp
创建的堆栈帧。如果ESP尚未指向保存的EBP值,则gcc会这样做。(enter
很慢,但与mov
/pop
相比,leave
只额外增加1个uop)@PeterCordes即使创建堆栈帧两次,如果嵌套正确也不会导致崩溃。但实际上,OP并不完全理解堆栈是如何工作的,以及为什么我们需要创建堆栈帧。我想上次查看时,我没有注意到OP在其中一个版本中有enter
。但是,是的,看起来完全不理解这样使用它的一部分。不过,如果您的回答建议完全忽略enter
,并始终使用push
/mov
(带有可选的子esp
或push
)来创建堆栈帧,我会更高兴<如果您在code golf中需要堆栈框架,则code>enter可能很有用,但我不认为像loop
、enter
或leave
这样的“高级”指令有助于初学者了解堆栈。@PeterCordes正是因为push/mov变体更清晰,我将其添加到了答案中。但在我看来,仅仅因为功能更复杂而忽略这些功能是错误的。至少OP已经对进入/离开有所了解。还要注意,这个示例实际上非常愚蠢,因为它根本不需要任何堆栈帧。我甚至无法说出OP希望这段代码做什么。我的目标只是展示如何使代码正确终止。我是说,如果我是为初学者授课,我不会提到loop
或enter
。ISA ref手册适用于任何想去挖掘并找到它们的人,或其他复杂的东西,如rep movsb
,shld
,pusha
,xlat
或任何其他他们不需要的指令(或某些指令)。但你是对的,如果他们已经在询问进入/离开的问题,你不应该在回答中遗漏它。
format PE
entry main
foo:
push ebp
mov ebp, esp
sub esp, 12
mov BYTE [ebp-1], al
mov DWORD [ebp-8], edi
mov DWORD [ebp-12], esi
mov esp, ebp
pop ebp
ret
main:
push ebp
mov ebp, esp
sub esp, 16
mov DWORD [ebp-4], edi
mov DWORD [ebp-16], esi
mov al, 97
mov edi, 43
mov esi, 76
call foo
mov esp, ebp
pop ebp
xor eax, eax ; exit code
ret
format binary as "com"
org 100h
mov ah,09
mov dx,msg
int 21h
mov ah,08
int 21h
int 20h
msg db "hello world!$"
$dosbox myprog.com