如何在编译时检测NASM的架构,以便为x64和x86拥有一个源代码?

7
我正在寻找一些nasm的预处理器功能,可以在x86和x64架构中使用相同的源代码。类似于C预处理器使用的ifdef some_constant,用于检测编译是否在Windows或Linux上进行。
编辑
我知道nasm标志。我使用它们。我只是想要完全相同的源代码,并期望预处理器根据这些标志正确处理它。我将使用#ifdef ... else来进行堆栈操作等,对于两种架构具有相同的核心代码。

这两种架构是不同的。你将无法利用额外的寄存器等优势。坚持使用32位代码,或考虑使用编译但足够低级的语言,如C语言。 - Seva Alekseyev
这取决于可执行格式中的标志,因此您不能同时拥有两种架构。 - phuclv
4个回答

4

__OUTPUT_FORMAT__

http://www.nasm.us/doc/nasmdoc4.html#section-4.12.6

The __OUTPUT_FORMAT__ standard macro holds the current Output Format, as given by the -f option or NASM's default. Type nasm -hf for a list.

%ifidn __OUTPUT_FORMAT__, win32 
  %define NEWLINE 13, 10 
%elifidn __OUTPUT_FORMAT__, elf32 
 %define NEWLINE 10 
%endif

我尝试使用 OUTPUT_FORMAT 来区分 elf32 和 elf64,但没有任何结果。 - Agguro
@Agguro,感谢您的报告。您能否在NASM问题跟踪器/邮件列表上开一个问题,并在此处链接到它? - Ciro Santilli OurBigBook.com

2
在NASMX包中的syscalls.inc文件中,你可以找到%if BITS == 64 这一行。这决定了你是否使用nasm的64位或32位版本。也许这就是你想知道的内容?

2

NASM无法检测架构,但您可以使用输出格式(命令行选项:-felf、-felf32、-felf64、-fwin32等)来满足您的需求。请阅读友好手册


那么预处理器不能利用这些标志,让程序员使用像#ifdef x64 do_sth1 else do_sth2这样的宏吗? - infoholic_anonymous
@infoholic_anonymous:你可以在x64系统上构建和运行32位程序。那么架构检测有什么意义呢?但是你可以检索构建选项(__OUTPUT_FORMAT__)。你读过手册了吗?如果你通过脚本构建程序,你可以使用uname -m来检索机器。这里有更多的提示:https://dev59.com/ZW855IYBdhLWcg3w5Igb。 - rkhb
我正在做一个非常简单的项目,需要为x64和x86提供代码。我的代码差异很小,主要涉及调用约定的一个位置以及寄存器名称之类的问题。寄存器名称可以通过定义进行替换,调用约定可以通过几行ifdef进行处理。为什么我要保留两个文件并在更改时进行双重校正?我很惊讶,这似乎很奇怪,在命令行程序的C源代码中,有些代码部分依赖于操作系统是相当普遍的。 - infoholic_anonymous

2
NASM允许您随意更改代码大小(使用bits指令),这使得您可以在elf64中拥有16位或32位代码,或者在elf32中拥有64位代码。因此,检测输出格式相对来说是不准确的(脆弱)。
相反,您需要检测当前的代码大小。为此,NASM有一个名为__BITS__的标准宏。这意味着您可以执行%if __BITS__ = 64。
然而,32位代码和64位代码通常使用完全不同的调用约定;而64位代码具有更多的寄存器、更宽的寄存器和其他差异(如果不使用额外的寄存器或额外的宽度,意味着代码质量会非常差——远不如编译器生成的代码)。这意味着(除了仅用于一些小型宏之外),试图在同一代码中支持32位和64位是极其愚蠢的。您最终只会得到完全不同的代码,针对完全不同的情况,这些代码被放入同一个文件中,没有任何合理的原因,并且使用预处理器魔术分离开来,以解决一开始就没有意义的问题。
更明智的方法是为不同的情况设置单独的文件(例如src/arch/x86_32目录和src/arch/x86_64目录),在这种情况下,您可以让构建脚本或makefile进行排序(例如告诉汇编器使用不同的“包含路径”)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接