void foo(){
...
}
将此编译为程序集,似乎linux上的gcc
将创建标签foo
作为入口点,但在OSX上标记为_foo
。
当然,我们可以在需要标签时进行特定于操作系统的选择,但这很麻烦。
有没有办法抑制这种情况,以便两个系统上的标签相同(最好是与Windows兼容的标签)?
答案 0 :(得分:2)
没有。它是该平台名称修改规范的一部分。
你不能改变它。你还在写集会。不要指望它以任何方式移植,这就是C的发明。
答案 1 :(得分:0)
早期的C编译器使用_
修饰了函数的名称,以避免在链接已经开发的庞大的时代汇编库时发生名称冲突。
此信息的信用点转到this excellent old answer 。
今天不再需要这个了,但传统仍然存在,主要是为了向后兼容,即使有些系统正在摆脱它。
这不是操作系统问题,操作系统与编程语言完全正交,名称修饰是不是由OS ABI定义的东西,它是编译器/链接器设计者的问题;虽然已经创建了标准来减少不兼容性,但ABI 可能建议使用它们。
为了完全理解如何缓解您的问题,值得注意的是,虽然OS API与语言无关,但C程序很少直接调用它们,更有可能使用C运行时。
C运行时通常是静态链接的,它希望根据用于创建它的编译器的方案来装饰名称。
因此,如果您需要使用C运行时,您必须坚持使用与系统组件使用相同的名称装饰。
最后一点排除了-fno-leading-underscore
选项,因为它会在相关平台上生成链接器错误。
最好处理汇编文件,因为您可以自由地定义和导入完全类型化的名称。此外,通常汇编代码是有限的。
如果你正在使用NASM 1 ,你可以使用一个很好的技巧,它被称为Macro indirection,它允许你附加一个符号,在命令行定义,一个名字。 考虑:
BITS 32
mov eax, %[p]data
_data db 0
data db 0
如果您编译此文件两次,第一次编译为nasm -Dp=_ ...
,第二次编译为nasm -Dp= ...
,通过检查生成的mov eax, %[p]data
操作码中的立即值,您可以检查第一种情况,它已被翻译为mov eax, _data
,第二种情况被翻译为mov eax, data
。
假设您通过将外部符号声明为EXTERN symn
来访问外部符号(这里的精确语法无关紧要),您可以定义一个宏PEXTERN
,其作用类似于指令EXTERN
,但导入符号为或者没有基于宏p
的值的前导下划线(您可以更改此名称)并为其定义别名,以便其导入的名称相同。
BITS 32
%macro PEXTERN 1
EXTERN %[p]%1
%ifnidn %1, %[p]%1
%define %1 %[p]%1
%endif
%endmacro
PEXTERN foo
PEXTERN bar
mov eax, foo
call bar
正在运行nasm -Dp= -e ...
和nasm -Dp=_ -e ...
会生成商家信息
extern foo extern _foo
extern bar extern _bar
mov eax, foo mov eax, _foo
call bar call _bar
您需要更新构建脚本/ Makefile,我可以使用两种方法:
检测操作系统类型并正确定义符号p
使用Makefile可能会更容易。
尝试编译测试程序
编写导入/导出函数的最小C程序和导出/导入该函数的最小汇编文件
将符号定义为_
并尝试汇编+编译(将所有内容重定向到 / dev / null )。
如果失败则将符号重新定义为空。
请注意,除了名称之外,各个操作系统可能还需要特定的程序集标志,因此通用构建脚本可能涉及更多但不一定无法管理。 你最终需要像 Cygwin 这样的东西。
1 如果没有,请检查您是否可以将想法移植到汇编程序中。