0

Im trying to change the character in a string in assembly, by accessing a certain bit in the rdi where the string address is placed. However, it is giving me a segfault. Please help

.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 Answers1

2

Initialized static data you want to modify at runtime goes in .data, not .text.

The .text section is mapped read+exec, .data is mapped read+write.

Compilers use .section .rodata for read-only static data, to group data separately from code. That sections is linked as part of the text segment.


If you want to put a 64-bit address in a register, you should use lea hello_world(%rip), %rdi

But if that was the problem (truncating the address to a 32-bit immediate from movq instead of movabs), you'd get a linker error.

So clearly you're linking this into a non-PIE executable on Linux (because you used printf not _printf (so it's not OS X where movq $symbol, %r64 will use a 64-bit absolute immediate), and didn't get link errors from using 32-bit absolute relocations for symbol addresses. Difference between movq and movabsq in x86-64

(On Linux, static addresses in position-dependent executables using the default code model fit in 32 bits.)


You can simplify your program to this, for a Linux non-PIE executable:

.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

compiles and runs correctly with gcc -no-pie hello-mutable.S && ./a.out, or fails to link with gcc -pie.

To build with -pie (the default on many modern distros), use lea hello_world(%rip), %rdi both times.


Of course you could also use puts instead of printf because your format string has no % chars in it. (Just remove the trailing \n.) Compilers do this optimization when compiling C. It's more efficient, and you wouldn't need to zero AL.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847