почему я не могу получить доступ к массиву с регистром в качестве смещения?

Я делаю код сборки (intel) и не понимаю, почему этот код не работает, когда я пытаюсь создать общую библиотеку:

BITS 64
SECTION .text
GLOBAL test
test:
push rbp
mov  rbp, rsp

mov rax, 3
mov  al, BYTE [rel array + rax]

pop  rbp
ret

SECTION  .data
array times 256 db 0

Принимая во внимание, что если вы измените строку с помощью «mov», изменив регистр на число, это сработает:

mov  al, BYTE [rel array + 3]

У меня нет ошибок с nasm, но когда я пытаюсь связать и создать общую библиотеку с помощью ld:

перемещение R_X86_64_32S против `.data' нельзя использовать при создании общего объекта; перекомпилировать с -fPIC

Я нашел этот ответ для ошибки «R_X86_64_32S»: связать работу на практике?

Но что то я не понимаю, почему я не могу использовать "rax" как смещение, тогда как с числом могу.

Есть ли способ просмотреть массив?

Это команды, которые я использую для создания общей библиотеки:

nasm -f elf64 test.s
ld -shared test.o -o test.so

person Michael Vouriz    schedule 20.03.2018    source источник
comment
Связано: stackoverflow.com/questions/43367427/: исполняемые файлы PIE имеют такое же ограничение на использование [array + rax], поскольку для этого требуется, чтобы адрес соответствовал 32-битному расширенному знаку значению. Как говорит Джестер, странно, что NASM не предупреждает об [rel array + rax], потому что rel не является опцией, поэтому он закодирован как [abs array + rax]. И, кстати, вы можете использовать default rel, чтобы NASM использовал RIP-относительно везде, где это возможно.   -  person Peter Cordes    schedule 21.03.2018


Ответы (1)


В длинном режиме (64-битном режиме) AMD представила относительную адресацию rip для x86. Если вы наберете

mov  al, BYTE [rel array + 3]

ассемблер генерирует операнд памяти для эффекта

mov  al, BYTE [array + 3 - $ + rip]

Это означает, что когда машинный код загружается по другому адресу, операнд памяти по-прежнему перемещается в нужное место, поскольку кодируется только относительное смещение array от инструкции, из которой на него ссылались, а не абсолютный адрес array, который не является абсолютным. t известно во время ссылки.

Теперь причина, по которой связывание не удается при использовании индексного регистра, заключается в том, что этот новый режим адресации заменяет предыдущий режим адресации disp32 (modr/m byte 05 +r). Он недоступен в режимах адресации SIB (масштаб/индекс/база) (фактически, предыдущий режим адресации disp32 по-прежнему доступен через операнд SIB без базы и индекса), поэтому ассемблер не может сгенерировать соответствующий операнд памяти для позиционно-независимый код.

Решение состоит в том, чтобы сначала загрузить абсолютный адрес array в некоторый регистр, используя lea, а затем получить доступ к членам массива относительно только что загруженного адреса:

lea rbx, [rel array]
mov al, byte [rbx + rax]
person fuz    schedule 20.03.2018
comment
Если nasm не выдает ошибку для [rel array + rax], то это ошибка. Он должен сказать вам, что это недопустимый режим адресации. - person Jester; 20.03.2018
comment
@fuz спасибо за ответ, но просто чтобы знать, это работает, если вы используете gcc для создания двоичного файла, почему это так? gcc должен выполнить связывание и должен потерпеть неудачу? - person Michael Vouriz; 20.03.2018
comment
[array + 3 - $ + rip] тоже не совсем верно. $ — это начало текущей инструкции, но адресация, относящаяся к RIP, относится к концу инструкции (т. е. к началу следующей). - person Peter Cordes; 20.03.2018
comment
@PeterCordes Я знаю. Однако добавление этого было бы немного сложным и утомительным для объяснения. - person fuz; 20.03.2018
comment
@PeterCordes В моем ответе говорится, что «этот новый режим адресации заменяет предыдущий режим адресации disp32». Как именно это неправильно? Я также прямо говорю, что режим адресации относительно рипа доступен только без SIB. Пожалуйста, прочитайте мой ответ еще раз, возможно, вы неправильно поняли предпоследний абзац. - person fuz; 20.03.2018
comment
Я думаю, что прочитал это задом наперед, например, изменение на [array + rax] заменяет .... Но вы говорили о том, что x86-64 заменяет одну форму режима адресации x86-32 [disp32]. И часть SIB / no-SIB верна, ИДК, как я неправильно это понял. Я только что проснулся и, по-видимому, не прочитал вопрос, прежде чем закрыть его как неправильный дубликат. Исправлено сейчас. - person Peter Cordes; 21.03.2018