如何在 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 main
到 nasm -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 设为本地,这样您就可以重复使用标签。
假设您有一个 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 main
到 nasm -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 设为本地,这样您就可以重复使用标签。