2015-03-28 4 views
2

У меня есть функция original_fun, определенная в одном файле (original_fun.c), и мне нужно сослаться на нее как global_alias в файле use_alias.c. Я попытался следующие:Как установить символ .globl в GAS?

# 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++ , и я хотел бы экспортировать его под более чистым именем, чтобы его можно было легко использовать с ассемблера.)

ГАЗА руководство (https://sourceware.org/binutils/docs/as/Set.html) говорится следующее:

Если вы .set глобальный символ, значение, хранящееся в файле объекта последнее значение, сохраненное в него.

Это может быть связано с моей проблемой, но я не уверен, что правильно понимаю это.

+0

Мой ответ: используйте «extern» C «или переосмыслите свой дизайн. Зачем вам нужно вызвать функцию из сборки? Не будет ли перегрузка решить проблему? Является ли это единственной перегрузкой, которая будет объявлена ​​'extern 'C"?? Не могли бы вы использовать функцию ввода, которая объявлена ​​'extern 'C"?? Если для функции требуются данные, которые вы генерируете с помощью сборки, почему это не в автономной процедуре сборки, которая может быть вызвана из 'original_fun', а не наоборот, как вы пытаетесь сделать? –

+0

Мне нужно вызвать функции (и обратиться к константам) из сборки, потому что ассемблер выводится из компилятора, а C++ - это язык библиотеки времени выполнения. Имена функций искажаются, даже если нет перегрузки, поскольку компилятор никогда не может быть уверен, что больше не будет перегрузок позже или в другом файле. –

ответ

2

Основная причина того, что вы пытаетесь сделать, не работает, потому что gas не знает «ценность» original_fun, как это внешний символ. При сборке ссылок на original_fun он может выдавать только директивы о перемещении, которые отличаются от фактического значения.

Вместо этого вместо этого следует сделать global_alias вид мягкого псевдонима для original_fun, чтобы он работал аналогично ему. Случается, что при каждом использовании global_alias в этом же файле происходит переключение на original_fun.Однако такой механик не может быть значимо экспортирован как фактическое значение global_alias, так как нет возможности выразить эту идею в ELF. (Я не знаю, может ли быть какой-либо объектный файловый формат, способный выражать символ как псевдоним для другого символа, и я не знаю, поддерживает ли это gas эту функцию при сборке в этот формат.)

Если вы хотите сделать работу global_alias, как вы ее описали, директива .set должна быть в том же сборочном узле, что и фактическое определение original_fun. Технически, если вы используете GCC, то вы можете сделать это с помощью встроенного ассемблера верхнего уровня:

void original_fun(int x) 
{ 
    printf("original_fun(%d)\n", x); 
} 
asm(".set global_alias, original_fun"); 

Это явно не портативный различных компиляторов, однако.

1

Мотивационный пример: original_fun - это искаженное имя C++, и я хотел бы экспортировать его под более чистым именем, чтобы его можно было легко использовать из ассемблера.

Подобно тому, как альтернативный ответ, чистое решение может быть использование extern "C":

extern "C" { 
    void original_fun(int x) 
    { 
     printf("original_fun(%d)\n", x); 
    } 
} 

Не только, что требуется меньше исходных файлов, но AFAIK это также переносимыми между различными компиляторами C++.

+0

Вот что я делаю прямо сейчас, но я бы хотел избежать одной половины моих функций в 'extern 'C", а остальное в моем 'namespace'. –

+2

@honzasp: Почему бы и нет? Поскольку вы все равно создаете для них символы верхнего уровня, что вам нужно потерять? Имейте в виду, что вы все еще можете использовать их внутри блока «пространство имен», заметьте; который совместим с 'extern 'C". – Dolda2000

+0

Если я объявляю функцию в глобальном пространстве имен (в 'extern" C "), мне нужно добавить префикс, чтобы избежать возможных конфликтов имен, и я считаю уродливым иметь некоторые имена с префиксом, а некоторые нет :) (это только причина мне нужен псевдоним) –

0

Если вы установили глобальный символ, значение, хранящееся в объектном файле, составляет последнее значение, хранящееся в нем.

Чтение этого, я считаю, это означает, что вы пытаетесь установить псевдоним на переменную, которая не может быть выполнена, я бы попытался использовать, но у меня нет возможности тестировать прямо сейчас!

const auto & new_fn_name = old_fn_name;

+1

Ссылка - это только замаскированный указатель, поэтому метка ассемблера 'new_fn_name' указывает на память слов, где сохраняется реальный адрес' old_fn_name'. –