Можно ли получить доступ к переменным, определенным в сборке, из C?

Могу ли я читать или записывать в переменную, определенную в моем файле сборки в моем файле C? Я не мог понять это самостоятельно. Например, файл C выглядит следующим образом:

int num = 33;

и производит этот ассемблерный код:

    .file   "test.c"
    .globl  _num
    .data
    .align 4
_num:
    .long   33

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

Я использую сборку mingw (32 бит) gnu в Windows 7.


person orustammanapov    schedule 11.03.2012    source источник
comment
не защищайся так :)   -  person UmNyobe    schedule 12.03.2012
comment
Когда я начал изучать ассемблер, я часто слышал, что скорость является причиной, по которой я должен выбирать сборку, а также меньший размер файла и все такое... Кто-то, кто способен вручную оптимизировать ассемблер лучше, чем компилятор точно знает, когда это уместно, а когда нет. Кажется, тебя еще нет. Ваш компилятор, вероятно, выводит лучшую сборку, чем вы (но это не означает, что нужно перестать учиться!).   -  person Ed S.    schedule 12.03.2012
comment
именно поэтому я задаю вопросы, даже если они могут показаться глупыми на первый взгляд   -  person orustammanapov    schedule 25.08.2012


Ответы (2)


Да, Linker объединяет все файлы .o (созданные из файлов .s) и создает один объектный файл. Таким образом, все ваши файлы c сначала станут файлами сборки.

Каждый файл сборки будет иметь список импорта и список экспорта. Список экспорта содержит все переменные, имеющие директиву .global или .globl. Список импорта содержит все переменные, начинающиеся с extern в файле c. (Однако GAS, в отличие от NASM, не требует объявления импорта. Все символы, которые не определены в файле, считаются внешними. быть определено где-то еще.)

Итак, если ваш файл сборки содержит это:

    .globl  _num        # _num is a global symbol, when it is defined
    .data               # switch to read-write data section
    .align 4
_num:                   # declare the label 
    .long  33           # 4 bytes of initialized storage after the label

Все, что вам нужно сделать, чтобы использовать num, это создать переменную extern, подобную этой

extern int num;  // declare the num variable as extern in your C code   

и тогда вы сможете прочитать его или изменить.


Многие платформы (Windows, OS X) добавляют начальное подчеркивание к именам символов, поэтому переменная C num имеет ассемблерное имя _num. Linux/ELF этого не делает, поэтому имя asm тоже будет num.

person theRealWorld    schedule 11.03.2012
comment
@Cherry: в вашем редактировании появилось несколько ошибок, которые я исправил в другом редактировании. Однако некоторые из них были связаны с вводящими в заблуждение частями исходного ответа. например .globl _num не объявляет _num, это означает только, что если он объявлен, он будет глобальным символом. В этом ответе пропущен _num: .long из вопроса. Вы никогда не захотите использовать переменные C с ведущими символами подчеркивания в их именах; они всегда зарезервированы для стандартной библиотеки и других частей реализации. На платформе ELF, где нет такой формы искажения имен, вы удаляете _ из asm, а не добавляете его в C. - person Peter Cordes; 21.12.2018

Да, вы можете обмениваться переменными в обоих направлениях. используйте .globl как у вас, а затем в C объявите внешнюю переменную, как если бы она была в другом модуле C, но вместо этого она находится в модуле asm.

person old_timer    schedule 11.03.2012
comment
Я пробовал, но возникли некоторые проблемы с компоновщиком, вот часть сборки: .global num num: .int 13 и мой файл C: #include <stdio.h> extern int num; int main() { printf("%d\n", num); } У меня проблема с компоновщиком: math.c:(.text+0xf): undefined reference to 'num' что я делаю не так? - person orustammanapov; 12.03.2012
comment
вы компилируете оба файла вместе или только ваш файл c? - person theRealWorld; 12.03.2012
comment
Я компилирую их следующим образом: gcc -m32 -o test test.c myasm.s - person orustammanapov; 12.03.2012
comment
@orustam имя переменной должно быть _num в ассемблерном файле. Вот еще одна ветка, посвященная этой проблеме с подчеркиванием на mingw. stackoverflow.com/questions/1034852/ - person Sam Liao; 12.03.2012
comment
@orustam, ты уверен, что _num в правильном разделе? Разве директива .data (и, возможно, .align в этом отношении) не должна появляться заранее? - person Brett Hale; 12.03.2012
comment
Арсан - СПАСИБО!!!! это сработало, я знал, что функции должны иметь символы подчеркивания, но никогда не слышал о переменных. когда я разобрал свой c-файл, gcc также добавил символы подчеркивания к моим переменным, и я должен понять это самостоятельно, но спасибо за вашу помощь. - person orustammanapov; 12.03.2012