Как использовать глобальную переменную во встроенной сборке gcc

Я пытаюсь использовать встроенный ассемблер для глобальной переменной, но компилятор выдает ошибку, говоря о неопределенной ссылке на saved_sp.

__asm__ __volatile__ (
        "movq saved_sp, %rsp\n\t" );

saved_sp глобально объявлен как static long saved_sp (для файла). Какую ошибку я здесь делаю?


person MetallicPriest    schedule 10.01.2012    source источник
comment
Разве вам не нужно передавать его через расширенные параметры asm?   -  person Mysticial    schedule 11.01.2012
comment
Как? Я не хочу использовать здесь какие-либо ограничения.   -  person MetallicPriest    schedule 11.01.2012
comment
Тогда я не знаю. Я всегда делаю это с помощью ограничений.   -  person Mysticial    schedule 11.01.2012
comment
Возможно, вы захотите указать свою gcc версию. На моем компьютере с Ubuntu gcc 4.4.4 доволен вашим кодом как есть.   -  person NPE    schedule 11.01.2012
comment
Я предлагаю вам включить короткий, но полный пример, который не компилируется для вас.   -  person NPE    schedule 11.01.2012
comment
Как насчет movq _saved_sp, %rsp, обратите внимание на дополнительное подчеркивание?   -  person Alexey Frunze    schedule 11.01.2012
comment
Почему бы вам просто не скомпилировать файл C в файл сборки, используя переключатель -S, и посмотреть, как компилятор называет переменную?   -  person Alexey Frunze    schedule 11.01.2012


Ответы (3)


Если происходит сбой с "неопределенной ссылкой на `saved_sp'" (что на самом деле является ошибкой компоновщика, а не ошибкой компилятора), когда saved_sp равно static, но работает, когда это не так, то вполне вероятно, что компилятор решил, что saved_sp не используется в вашем исходном файле, и поэтому решил полностью исключить его из скомпилированного кода, который передается ассемблеру.

Компилятор не понимает ассемблерный код внутри блока asm; он просто вставляет его в генерируемый им ассемблерный код. Таким образом, он не знает, что блок asm ссылается на блок saved_sp, и если больше ничего в коде C никогда не читает из него, он волен решить, что он полностью не используется, особенно если у вас включены какие-либо параметры оптимизации.

Вы можете сообщить gcc, что saved_sp используется чем-то, чего он не может видеть, и, таким образом, запретить ему выбрасывать его, добавив атрибут used (см. документация атрибутов переменных, примерно в середине страницы), например:

static long __attribute__((used)) saved_sp;

Вот полностью рабочий пример:

$ cat test.c
#ifdef FIXED
static long __attribute__((used)) saved_sp;
#else
static long saved_sp;
#endif

int main(void)
{
  __asm__ __volatile__ (
        "movq saved_sp, %rsp\n\t" );
}

$ gcc -m64 -o test test.c
$ gcc -m64 -O1 -o test test.c
/tmp/ccATLdiQ.o: In function `main':
test.c:(.text+0x4): undefined reference to `saved_sp'
collect2: ld returned 1 exit status
$ gcc -m64 -DFIXED -O1 -o test test.c
$ 

(Это из 32-битной системы сжатия Debian с gcc 4.4.5, которая мне больше всего подходит; -m64 вполне может быть ненужным в вашей системе.)

person Matthew Slattery    schedule 10.01.2012

Как я указал в комментариях, следующее компилируется (и генерирует правильный машинный код) с использованием gcc 4.4.4 в 64-битной Ubuntu:

long saved_sp;

int main() {
  __asm__ __volatile__ (
        "movq saved_sp, %rsp\n\t" );
}

Возможно, проблема может быть совершенно в другом (отсутствует #include, так что saved_sp на самом деле не определено? редактировать: теперь, когда вы говорите, что это static, я думаю, это маловероятно.)

person NPE    schedule 10.01.2012
comment
На самом деле я использовал static long save_sp. Если убрать статику, да работает нормально, но почему так? Почему компилятору не нравится статика здесь? - person MetallicPriest; 11.01.2012
comment
@MetallicPriest: я не могу воспроизвести это, с static или без него. - person NPE; 11.01.2012

Предпочтительно использовать входные и выходные параметры:

__asm__ __volatile__ ( 
    "movq %0, %%rsp\n\t"
    : : "r"(saved_sp) : "memory"
);

Часто могут быть некоторые переменные, которые вообще не являются символами на этапе сборки (например, переменные стека или регистры. Кроме того, вы хотите затереть всю память, чтобы гарантировать, что никакие переменные стека не хранятся в регистре после saved_sp хранится в РСП.

person Antti Haapala    schedule 30.07.2014