Сборка, x86: Как поместить метку в стек?
Учитывая данные:
.section data
data_set:
.long 2,5,33,54,2,76,4,37,43,223,98,70,255
как я помещаю начальный адрес данных (а не значение в этом адресе) в стек?
Я попробовал это:
pushl data_set
что в конечном итоге (после попытки доступа к данным по этому адресу) привело к segfault.
1 ответ
В синтаксисе AT&T, чтобы использовать адрес в качестве непосредственного операнда инструкции, используйте $label
,
Ты хочешь pushl $data_set
для push imm32
инструкция. как бы ты push $123
,
pushl data_set
будет толкать меч данных, загруженных с адреса data_set
т.е. push m32
,
Концептуально синтаксис AT&T рассматривает все как потенциальный адрес. Так label
это адрес, и так 0x123
, Так add 0x123, %eax
грузит с адреса 0x123
, а также add label, %eax
грузит с адреса label
, Когда вы хотите число в качестве непосредственного операнда, вы используете add $0x123, %eax
, Использование адреса символа в качестве непосредственного операнда работает идентично.
В любом случае, адрес закодирован в инструкции, это просто вопрос того, является ли он непосредственным или смещением в режиме адресации. Вот почему вы используете add $(foo - bar), %eax
добавить расстояние между двумя символами, а не add $foo-$bar, %eax
(который будет искать символ под названием $bar
то есть $
является частью имени символа). $
применяется ко всему операнду, а не к именам символов / меток. Связанный: больше о математике времени сборки в ГАЗЕ
В других контекстах, например, в качестве операнда .long
или же .quad
, нет немедленной проблемы с операндом памяти, поэтому вы просто пишете dataptr: .long data_set
испускать 4 байта данных, содержащих адрес data_set
, как вы получите от C static int *dataptr = data_set;
Вы могли бы проверить синтаксис, посмотрев на вывод компилятора C для
void ext(int*);
static int data[] = {1,2,3};
void foo() {
ext(data);
}
заставить компилятор C выдавать код, передающий символьный адрес функции. Я поместил это в проводник компилятора Godbolt, где он действительно использует pushl $data
,