2
votes

I'm having trouble solving a school exercise , I'm supposed to change a char array in c using inline assembly. In this case change "ahoy" to "aXoy", but I'm getting segmentation fault. This is my code:

 #include <stdio.h>

    int main() {
        char string[] = "ahoy";
        __asm__ volatile (
                "mov %0, %%eax;"
                "movb $'X', 1(%%eax);"
                : "=m"(string) : "0"(string) : "memory", "eax");
        printf("%s\n", string);
        return 0
    }

with this: "mov %0, %%eax;" I'm trying to store address of the array in register

then with this: "movb $'X', 1(%%eax);" I want to store byte 'X' in location pointed to by (%%eax) offset by 1 byte(char),

I have string both as output and input, and "memory","eax" in clobber since I'm modifying both. What is wrong with my code?

1
If you want to use string as input AND output then mark it as "+m" instead of "=m"and then drop the "0"(string) altogether. This line mov %0, %%eax; will move the 32-bit value AT the memory address to EAX since %0 is a memory operand. You want to put the ADDRESS of %0 in EAX it appears. Use lea %0, %%eax; instead of mov %0, %%eax; - Michael Petch
Secondly: Are you compiling this as 64-bit or 32-bit code? The inline assembly as is using a 32-bit register with a stack based address (string) will fault since the stack address can't be represented properly in a 32-bit value. Make sure you compile this with -m32 or modify the code to use a 64-bit register for the address (RAX instead of EAX) - Michael Petch
__asm__ volatile ( "lea %0, %%eax;" "movb $'X', 1(%%eax);" : "+m"(string) :: "memory", "eax"); - Michael Petch
The + modifier has been around for almost forever. They are all documented here: gcc.gnu.org/onlinedocs/gcc/Modifiers.html#Modifiers - Michael Petch
Technically speaking in this case using +m you don't need to use the memory clobber since the compiler will realize all of the string in memory first since you are using an m constraint. Alternatively you could have done __asm__ volatile ( "movb $'X', 1(%0);" :: "r"(string) : "memory"); . Memory clobber would be needed since in this case you are passing the address of string through a register and not a memory operand. - Michael Petch

1 Answers

1
votes

Use gcc -S instead of -c to look at the compiler's assembly output and you should see what's wrong. The "m" constraint produces a memory reference expression for accessing the object associated with it, not a register containing its address. So it will expand to something like (%ecx), not %ecx, and the first mov will load 4 bytes from string, rather than the address of string, into eax.

One way to fix this would be to use a register constraint "r"(string) instead.

Alternatively you could replace the mov with lea: lea %0, %%eax.

There are other issues with your code too like the useless temporary/clobber register eax but they shouldn't keep it from working.