如何在 NASM 中仅包含从一个文件到另一个文件的指定标签?

How can one include only specified labels from one file to another in 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的用户,你并不是真的对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 哪些标签有用,应该 exported/imported,哪些不应该?

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

Use local labels. nasm.us/doc/nasmdoc3.html section 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

7 行将跳转到第 5 行,因为它们都是本地的并且在 label2 之后。所以可以把不应该是external的labels改成local,不会发生冲突:

library.asm

section   .text

useful_func:
    push rbp
    mov rbp, rsp

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

    mov rsp, rbp
    pop rbp
    ret

main.asm

%include "library.asm"

section   .text
global    _start       

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

Another way to solve this is to mark the labels you want to export as global and then link the files together instead of relying on the %include directive.

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

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

library.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

main.asm

extern useful_func    ; Now extern

section   .text
global    _start

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

注意:即使您决定使用此方法,我还是建议您将 loops/conditionals 设为本地,这样您就可以重复使用标签。