I was using coding exercise site; I write and submit code that can solve provided problem, and then the system runs against predetermined test cases and judge whether the code is valid.
I'm currently practicing x86-64 NASM.
I wrote some code that includes read-only string table. But, the system emitted compile error related to PIE scheme.
When I place my string table to .data
instead of .rodata
, the system accepts my code.
Although my code is accepted, I want to know how to write proper read-only string table that can be placed to .rodata
section.
This is part of string table which is placed on .rodata
section:
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
I got following error from system when I submitted this code:
/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
When I changed to .data
instead of .rodata
, the system accepted without any error.
As far as I know, if it were executable code, I could use RIP-relative address mode, like lea rsi, [rel .Leucine]
. I want to know how to get similar effect regarding string table.
The string table must be writable at some point as the addresses you put in it are only known at runtime. Ideally, the table would be writable initially, then the runtime link editor patches in the correct addresses, and then it's set to read-only.
While ELF does not provide this feature on its own, there's a GNU extension available on Linux for it: any section named .data.rel.ro
or one of its subsections will be mapped read/write at program start, then the runtime linker patches in relocations, and then it's remapped as read-only. This allows you to get the desired effect, e.g. do:
; 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