如何在程序集x86中更改字符串中的字符(AT&T语法)

时间:2018-10-15 19:59:09

标签: assembly x86 att

我试图通过访问放置字符串地址的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

1 个答案:

答案 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

,并且不会因使用32位绝对地址重定位符号地址而导致链接错误。

(在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设为零。