NASM汇编程序 - 如何确保功能标签不会再执行一次?

时间:2018-01-17 18:42:03

标签: assembly x86

您好我正在修补汇编级编程。我有以下代码

    mov al, 'H'
    call my_function

my_function:
    mov ah,0x0e            ; BIOS print-character
    int 0x10
    ret

    jmp $                  ; infinite loop because there's no OS to exit to

times 510-($-$$) db 0
dw 0xaa55                  ; boot sector signature

我有一个用于打印al内容的标签,该标签按预期工作(打印H)。但是在函数返回之后,再次执行相同的标签并打印额外的H。这是可以理解的,因为ret从堆栈中弹出了地址,将地址指向调用者并再次执行标签。

现在我的问题是,如何避免这种情况?我不能只使用像实际功能这样的标签而不打印两次吗?我不想要额外的执行,这可能会改变我的计划。

2 个答案:

答案 0 :(得分:7)

正如Jester在评论中所说,所有应该是功能的标签必须低于jmp $声明,因此它不会执行额外的时间。
附: jmp $指示系统跳转到当前位置,导致无限循环,不允许在函数存在的地方继续前进。

答案 1 :(得分:6)

CPU看不到你的标签,它从指令到指令。

除非当前指令是某种跳转(grepcall也是某种跳转) - 在CPU完成当前指令后,它将转到下一个,它

执行ret时,它将执行函数内的所有指令,然后在执行call my_function时,它将返回ret之后的下一条指令。

下一条指令再次是call的第一条指令,第二次执行......第二次点击my_function后,它实际上会丢失谁知道哪里({{ 1}}将在堆栈顶部取值并将其用作下一条指令的地址,因此在第二次ret发生时堆栈中的任何内容,您的代码现在正在运行... )

汇编源不仅仅是指令组,而是将它们放在内存中,并通过一个接一个地放置一条指令来控制代码流。 CPU将按顺序逐行执行它们,就像你编写它们一样(除非你通过使用某种类型的跳转来改变代码流,否则你可以跳过几行源代码)。

因此,如果您希望CPU在ret完成"之后停止,并且您正在创建引导加载程序,即无法返回(没有操作系统,或者某些东西)像那样),你将通过无限循环在主结尾处创建死胡同,如:

ret

那"主要结束"就在main之后。 "创建my_function"本身必须在" main"之外定义,例如在此无限循环停止之后。

也许你错过了dead_end_loop: pause ; give CPU hint this is idling loop ; so it will save power by switching off some circuitry jmp dead_end_loop 的内容以及它在源代码中的用途。在这种情况下,call my_function符号表示汇编程序"当前指令/行的地址",因此jmp $可以转换为"跳转到同一行",这意味着它是一个无限循环,CPU将永远不会执行除$指令之外的任何其他操作(除非设置为处理某些中断信号,否则任何此类外部信号都会导致CPU将执行切换到特定的中断处理程序代码,因为程序员/操作系统在进入无限循环之前确实配置了它。)

还有一个想法:您可能需要查看https://schweigi.github.io/assembler-simulator/和"步骤"在几个例子中,看看CPU是如何看到源的,但只看到机器代码字节(右侧可见"内存"),以及它如何从一条指令转到下一条指令, jmp $如何变化等......