首页 > 解决方案 > 如何在 NASM 中仅包含从一个文件到另一个文件的指定标签?

问题描述

假设您有一个library.asm,其中包含一个具有循环的函数:

section   .text 

useful_func:
    push rbp
    mov rbp, rsp

    loop0:
        ; Do useful stuff...
        jnz loop0

    mov rsp, rbp
    pop rbp
    ret

和一个包含库并调用该函数的main.asm :

%include "library.asm"

section   .text
global    _start 

_start:
    ; Do stuff
    call useful_func
    ; Do more stuff

当然,作为library.asm的用户,您对 label 并不真正感兴趣loop0,您实际上对useful_func. 但是,两个标签都是导入的。因此,如果您将main.asm更改为:

%include "library.asm"

section   .text
global    _start 

_start:
    ; Do stuff
    loop0:
        call useful_func
        jnz loop0
    ; Do more stuff

你得到一个错误,因为标签loop0被定义了两次。

那么,有没有办法向 NASM 指定哪些标签有用并且应该导出/导入,哪些不应该?

注意:没有必要使用该%include命令,它只是我知道从 NASM 中的另一个文件导入的唯一方法。如果有更好、更灵活的命令/方式来做到这一点,我们也很感激。

标签: assemblyincludenasm

解决方案


使用本地标签。nasm.us/doc/nasmdoc3.html 第 3.9 节

本地标签以 , 开头.,可以在代码上使用任意多次。每个本地标签都绑定到最后一个非本地标签。在这个例子中:

1 label1:
2     .loop:            ; Implicitly label1.loop
3         ;stuff
4 label2:
5     .loop:            ; Implicitly label2.loop
6         ;other stuff
7 jmp .loop             ; Implicitly label2.loop

line7将跳转到 line 5,因为它们都是 local 和 after label2。所以你可以更改不应该在本地外部的标签,并且不会发生冲突:

库.asm

section   .text

useful_func:
    push rbp
    mov rbp, rsp

    .loop0:                      ; Now local
        ; Do useful stuff...
        jnz .loop0

    mov rsp, rbp
    pop rbp
    ret

主程序

%include "library.asm"

section   .text
global    _start       

_start:
    ; Do stuff
    .loop0:
        call useful_func
        jnz .loop0
    ; Do more stuff

解决此问题的另一种方法是将要导出的标签标记为全局标签,然后将文件链接在一起,而不是依赖 %include 指令。

如果您不介意更改链接和编译(例如从nasm -f elf64 main.asm && ld main.o -o mainto nasm -f elf64 library.asm && nasm -f elf64 main.asm && ld library.asm main.o -o main),那么您可以使用global/extern指令(阅读此文档第 6.5 和 6.6 节了解更多详细信息)而不是%include.

使用此方法,您将只导出使用/声明的特定标签。所以你可以用它来避免冲突:globalextern

库.asm

global useful_func    ; Now global

section   .text

useful_func:
    push rbp
    mov rbp, rsp

    loop0:
        ; Do useful stuff...
        jnz loop0

    mov rsp, rbp
    pop rbp
    ret

主程序

extern useful_func    ; Now extern

section   .text
global    _start

_start:
    ; Do stuff
    loop0:
        call useful_func
        jnz loop0
    ; Do more stuff

注意:即使您决定使用此方法,我还是建议您将循环/条件设置为本地,以便您可以重用标签。


推荐阅读