Инициализированные статические данные, которые вы хотите изменить во время выполнения, поступают в .data
, а не .text
.
Раздел .text
сопоставляется как read + exec, .data
сопоставляется как read + write.
Компиляторы используют .section .rodata
для статических данных только для чтения, чтобы группировать данные отдельно от кода.Эти разделы связаны как часть текстового сегмента .
Если вы хотите поместить 64-битный адрес в регистр, вы должны использовать lea hello_world(%rip), %rdi
Но если бы это была проблема (усечение адреса до 32-битного значения сразу с movq
вместо movabs
), вы получите ошибку компоновщика.
Итак, вы явно связываете этов не-PIE исполняемый файл в Linux (потому что вы использовали printf
, а не _printf
(так что это не OS X, где movq $symbol, %r64
будет использовать 64-битный абсолютный немедленный запрос), и не получил ошибок ссылок при использовании 32-Битовые абсолютные перемещения для символьных адресов. Разница между movq и movabsq в x86-64
(В Linux статические адреса в зависимых от позиции исполняемых файлах, использующих модель кода по умолчанию, помещаются в 32 бита.)
Вы можете упростить свою программу до этого, для исполняемого файла Linux без PIE:
.data # mutable static data
hello_world: .asciz "hellothere \n"
#.section .rodata # read-only static data
.text # code
.global main
main:
mov $hello_world, %edi # most efficient way to put a static addr in a reg
# in a position-dependent executable
xor %eax,%eax # most efficient way to zero the whole 64-bit reg
call printf
mov $hello_world, %edi
movb $'a', (%rdi) # store directly to memory instead of using a partial register
xor %eax,%eax
call printf
xor %eax,%eax # return 0, otherwise you might as well jmp printf
ret # might as well just ret instead of calling exit since this is main, not _start
компилируется и работает правильно с gcc -no-pie hello-mutable.S && ./a.out
, или не может связаться с gcc -pie
.
Для сборки с -pie
(по умолчанию во многих современных дистрибутивах), используйте lea hello_world(%rip), %rdi
оба раза.
Конечно, вы также можете использовать puts
вместо printf
, потому что в строке формата нет символов %
.(Просто удалите завершающий \n
.) Компиляторы выполняют эту оптимизацию при компиляции C. Это более эффективно, и вам не нужно обнулять AL.