Я использовал сайт упражнений по программированию; Я пишу и отправляю код, который может решить указанную проблему, а затем система запускает заранее определенные тестовые примеры и оценивает, действителен ли код.
В настоящее время я практикую x86-64 NASM.
Я написал код, который включает таблицу строк, доступную только для чтения. Но система выдала ошибку компиляции, связанную со схемой PIE.
Когда я помещаю свою таблицу строк в .data
вместо .rodata
, система принимает мой код.
Хотя мой код принят, я хочу знать, как написать правильную таблицу строк, доступную только для чтения, которую можно поместить в раздел .rodata
.
Это часть таблицы строк, которая находится в разделе .rodata
:
section .rodata
align 8, db 0
table:
dq .Leucine ; UUA
dq .Phenylalanine ; UUC
dq .Phenylalanine ; UUU
dq .Leucine ; UUG
dq 0 ; UGA
dq .Cysteine ; UGC
dq .Cysteine ; UGU
dq .Tryptophan ; UGG
.Leucine:
db "Leucine", 0
.Phenylalanine:
db "Phenylalanine", 0
.Cysteine:
db "Cysteine", 0
.Tryptophan:
db "Tryptophan", 0
Когда я отправил этот код, я получил следующую ошибку в системе:
/usr/lib/gcc/x86_64-alpine-linux-musl/12.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: protein_translation.o: warning: relocation in read-only section `.rodata'
/usr/lib/gcc/x86_64-alpine-linux-musl/12.2.1/../../../../x86_64-alpine-linux-musl/bin/ld: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make: *** [Makefile:32: tests] Error 1
Когда я изменил на .data
вместо .rodata
, система приняла без ошибок.
Насколько я знаю, если бы это был исполняемый код, я мог бы использовать режим адреса относительно RIP, например lea rsi, [rel .Leucine]
. Я хочу знать, как получить аналогичный эффект в отношении таблицы строк.
В какой-то момент таблица строк должна быть доступна для записи, поскольку адреса, которые вы в нее помещаете, известны только во время выполнения. В идеале изначально таблица должна быть доступна для записи, затем редактор ссылок во время выполнения исправляет правильные адреса, а затем она становится доступной только для чтения.
Хотя ELF не предоставляет эту функцию сам по себе, в Linux для нее доступно расширение GNU: любой раздел с именем .data.rel.ro
или один из его подразделов будут отображаться для чтения/записи при запуске программы, затем компоновщик времени выполнения исправляет перемещения, а затем он переназначается только для чтения. Это позволяет получить желаемый эффект, например. делать:
; this data should be read-only at runtime, but must be writable while the
; dynamic linker fixed up relocations
section .data.rel.ro progbits alloc noexec write align=8
table:
dq .Leucine ; UUA
dq .Phenylalanine ; UUC
dq .Phenylalanine ; UUU
dq .Leucine ; UUG
dq 0 ; UGA
dq .Cysteine ; UGC
dq .Cysteine ; UGU
dq .Tryptophan ; UGG
; this section is properly readonly
section .rodata
.Leucine:
db "Leucine", 0
.Phenylalanine:
db "Phenylalanine", 0
.Cysteine:
db "Cysteine", 0
.Tryptophan:
db "Tryptophan", 0
Спасибо за ответ. Мой код успешно скомпилирован и принят. Я попытался изменить содержимое таблицы, например mov qword [table], -1
, но, как и ожидалось, это не удалось.
Одним из решений было бы заменить
dq .Leucine
наdd .Leucine - table
, затем загрузить двойное слово в регистр и добавить адрес таблицы. Чтобы использоватьrel
адресацию, вам нуженlea REG1, [rel table]
, затем загрузите двойное слово из таблицы + индекс в REG2 (расширение нуля до 64-битного регистра путем записи в 32-битный регистр) и адресуйте строку, начиная с[REG1 + REG2]
. Заполнители следует заменить реальными именами регистров по вашему выбору; адресацию необходимо выполнять с помощью 64-битных регистров, но вы можете использовать размер двойного слова (4 байта) для записей таблицы. Вам все равно придется обрабатывать запись 0.