我在一个文件(original_fun
)中定义了一个函数original_fun.c
,我需要在文件global_alias
中将其称为use_alias.c
。我尝试了以下方法:
# set_alias.s
.globl global_alias
.set global_alias, original_fun
// original_fun.c
#include <stdio.h>
void original_fun(int x)
{
printf("original_fun(%d)\n", x);
}
// use_alias.c
extern void global_alias(int x);
int main()
{
global_alias(42);
return 0;
}
但不导出符号global_alias
:
$ as set_alias.s -o set_alias.o
$ clang original_fun.c -c -o original_fun.o
$ clang use_alias.c -c -o use_alias.o
$ clang set_alias.o original_fun.o use_alias.o -o result
use_alias.o: In function `main':
use_alias.c:(.text+0x1d): undefined reference to `global_alias'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
objdump
报告:
$ objdump -rt set_alias.o
set_alias.o: file format elf32-i386
SYMBOL TABLE:
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 *UND* 00000000 original_fun
(激励的例子是original_fun
是一个受损的C ++名称,我希望以更干净的名称导出它,以便可以从汇编程序中轻松使用它。)
GAS手册(https://sourceware.org/binutils/docs/as/Set.html)声明如下:
如果设置了全局符号,则存储在目标文件中的值是存储在其中的最后一个值。
这可能与我的问题有关,但我不确定我是否理解这一点。
答案 0 :(得分:3)
您尝试做的事情之所以不起作用的基本原因是因为gas
并不知道&#34;值&#34; original_fun
,因为它是外部符号。在汇编对original_fun
的引用时,它只能发出重定位指令,这与发出它的实际值不同。
然后.set
代替global_alias
本地使original_fun
成为global_alias
的一种软别名,以便它与它类似。发生的情况是,同一文件中original_fun
的每次使用都会重新定位到global_alias
。但是,这样的机制不能有意义地导出为gas
的实际值,因为没有办法在ELF中表达这个想法。 (我不知道是否有某种对象文件格式能够将符号表示为另一个符号的别名,我也不知道global_alias
在组装到该格式时是否支持该功能。)
如果您希望.set
按照您的描述工作,original_fun
指令需要与void original_fun(int x)
{
printf("original_fun(%d)\n", x);
}
asm(".set global_alias, original_fun");
的实际定义位于同一个装配单元中。从技术上讲,如果您使用GCC,那么您可以使用顶级内联汇编来执行此操作:
{{1}}
然而,对于不同的编译器来说,这显然是不可移植的。
答案 1 :(得分:1)
激励的例子是original_fun是一个受损的C ++名称,我想以更干净的名称导出它,以便可以从汇编程序中轻松使用它。
作为替代答案,更清洁的解决方案可能是使用extern "C"
:
extern "C" {
void original_fun(int x)
{
printf("original_fun(%d)\n", x);
}
}
这不仅需要更少的源文件,而且AFAIK也可以在不同的C ++编译器之间移植。
答案 2 :(得分:0)
如果设置全局符号,则存储在目标文件中的值为 存储在其中的最后一个值。
读这个我相信这意味着你试图将别名设置为一个无法完成的变量,我会尝试使用但我现在无法测试!
const auto&amp; new_fn_name = old_fn_name;