我试图通过访问放置字符串地址的rdi中的某个位来更改汇编字符串中的字符。但是,这给了我一个段错误。请帮助
.text
hello_world: .asciz "hellothere \n"
.global main
main:
movq $hello_world, %rdi
movq $0, %rax
call printf
movq $hello_world, %rdi
movb $'a', %r10b
movb %r10b, (%rdi)
movq $0, %rax
call printf
call exit
答案 0 :(得分:0)
您要在运行时修改的初始化静态数据放在.data
中,而不是.text
中。
.text
部分映射为读+执行,.data
部分映射为读+写。
编译器将.section .rodata
用于只读静态数据,以将数据与代码分开进行分组。该部分链接为part of the text segment。
如果要在寄存器中放入64位地址,则应使用lea hello_world(%rip), %rdi
但是,如果那是问题所在(将地址从movq
而不是movabs
截断到32位立即数),则会出现链接器错误。
因此很明显,您正在将其链接到Linux上的非PIE可执行文件(因为您使用的是printf
而不是_printf
(因此,不是OS X的movq $symbol, %r64
将使用64- Difference between movq and movabsq in 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设为零。