assembly - NASM 汇编器 - 如何确保函数标签不会被额外执行一次?

标签 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 从堆栈中弹出地址,将其指向调用者并再次执行标签。

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

最佳答案

CPU 不会看到你的标签,它会从一条指令转到另一条指令。

除非当前指令是某种跳转(callret 也是某种跳转) - CPU 处理完当前指令后,它将继续执行到下一个,跟随它。

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

下一条指令又是my_function的第一条指令,第二次执行...第二次点击ret后,谁知道它实际上会丢失-where(ret 将获取堆栈顶部的值并将其用作下一条指令的地址,因此无论发生第二个 ret 时堆栈中的内容,您的代码现在正在疯狂运行...)

汇编源代码不仅仅是一组指令,而且您还可以将它们定位在内存中,并通过将一条指令放置在另一条指令中来控制代码流。 CPU 将按顺序逐行执行它们,就像您编写它们一样(除非您通过使用某种跳转来更改代码流程,然后您可以跳过几行源代码)。

因此,如果您希望 CPU 在您的 main “完成”后停止,并且您正在创建引导加载程序,即没有任何可返回的内容(没有操作系统或类似的东西),您将通过无限循环在 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

“main 结束”就在调用 my_function 之后。 “my_function”本身必须在“main”之外定义,例如在此无限循环停止程序之后。

<小时/>

也许您错过了jmp $ 是什么以及它在源代码中的用途。这种情况下的 $ 符号对于汇编器来说意味着“当前指令/行的地址”,因此 jmp $ 可以翻译为“跳转到同一行”,这意味着它是一个无限循环,除了这个jmp $指令之外,CPU永远不会执行任何其他指令(除非它被设置为处理某些中断信号,那么任何此类外部信号都会导致CPU将执行切换到特定的中断处理程序代码,因为程序员/操作系统在进入无限循环之前对其进行了配置)。

<小时/>

还有一个想法:您可能需要检查https://schweigi.github.io/assembler-simulator/并“单步”几次示例,看看 CPU 如何看不到源代码,而只看到机器代码字节(在右侧显示为“内存”),以及它如何从一条指令到下一条指令,如何IP正在改变,等等...

关于assembly - NASM 汇编器 - 如何确保函数标签不会被额外执行一次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48307937/

相关文章:

macos - 在OSX x64程序集中使用RIP相对寻址

assembly - 是什么阻止您单独运行目标文件?

c - GCC x86 内联汇编中的 (+r) 与 (=r) 约束

assembly - 汇编语言中的 ecx 递增

assembly - 英特尔 TSX 前缀是否作为 NOP 在 AMD 上(安全)执行?

c++ - 未定义的行为是否适用于 asm 代码?

visual-studio - 如何定义一个占用多个其他变量空间的变量?

assembly - 当处理器试图访问一个不存在的物理地址时会发生什么?

c++ - 使用 x86 汇编程序访问二维数组

assembly - 我们何时以及为何签署扩展并使用带有 mul/div 的 cdq?