Как создать таблицу строк .rodata, когда PIE включен?

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

В настоящее время я практикую 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]. Я хочу знать, как получить аналогичный эффект в отношении таблицы строк.

Одним из решений было бы заменить dq .Leucine на dd .Leucine - table, затем загрузить двойное слово в регистр и добавить адрес таблицы. Чтобы использовать rel адресацию, вам нужен lea REG1, [rel table], затем загрузите двойное слово из таблицы + индекс в REG2 (расширение нуля до 64-битного регистра путем записи в 32-битный регистр) и адресуйте строку, начиная с [REG1 + REG2]. Заполнители следует заменить реальными именами регистров по вашему выбору; адресацию необходимо выполнять с помощью 64-битных регистров, но вы можете использовать размер двойного слова (4 байта) для записей таблицы. Вам все равно придется обрабатывать запись 0.

ecm 01.09.2024 19:04
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
1
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Хотя 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, но, как и ожидалось, это не удалось.

Venusaur 03.09.2024 03:46

Другие вопросы по теме