user45698746
user45698746

Reputation: 325

Why "mov %%rsp, %%rbp" causing Segmentation fault?

I'm new in inline assembly. I have the following C function with inline assembly. I'm just trying to see if push %%rbp and mov %%rsp, %%rbp actually operating correctly. My function is following,

test_inlineAssemblyFunction(){

    u64 base, rsp, base1, rsp1;
    asm volatile(

            "mov %%rbp, %0 \n"
            "mov %%rsp, %1 \n"

            "push %%rbp \n"
            "mov %%rbp, %2 \n"

            "mov %%rsp, %%rbp \n" <--- this line is causing the problem
            "mov %%rbp, %3 \n"
            :"=r"(base), "=r"(rsp),"=r"(base1), "=r"(rsp1)
            :
            : "rax","rbx","rsp"
            );
    printf("Before: Base register %x\n", base);
    printf("Before: stack pointer register %x\n", rsp);
    printf("After: (Should be same as previous )Base register %x\n", base1);
    printf("After: (Actually %rsp-8)Base register %x\n", rsp1);

    
}

output:

Before: Base register ee050e50
Before: stack pointer register ee050e20
After: (Should be same as previous )Base register ee050e50
After: (Actually %rsp-8)Base register ee050e18
Segmentation fault (core dumped)

From the output, I can see that all the print statement is printing the desired output. But then the segmentation fault. If my understanding is correct Segmentation Fault occurs when trying to read or write an illegal memory location. So, In my case, "mov %%rsp, %%rbp \n" is causing Segmentation fault, So I'm not allowed to read rsp from userspace?

Update: As @Kuba hasn't forgotten Monica suggested, Following is the disassembly of test_inlineAssemblyFunction function,

(gdb) disas test_inlineAssemblyFunction
Dump of assembler code for function test_inlineAssemblyFunction:
0x0000000000007366 <+0>:    push   %rbp
0x0000000000007367 <+1>:    mov    %rsp,%rbp
0x000000000000736a <+4>:    push   %rbx
0x000000000000736b <+5>:    sub    $0x28,%rsp
0x000000000000736f <+9>:    mov    %rbp,%rdi
0x0000000000007372 <+12>:   mov    %rsp,%rsi
0x0000000000007375 <+15>:   push   %rbp
0x0000000000007376 <+16>:   mov    %rbp,%rcx
0x0000000000007379 <+19>:   mov    %rsp,%rbp
0x000000000000737c <+22>:   mov    %rax,%rdx
0x000000000000737f <+25>:   mov    %rdi,-0x30(%rbp)
0x0000000000007383 <+29>:   mov    %rsi,-0x28(%rbp)
0x0000000000007387 <+33>:   mov    %rcx,-0x20(%rbp)
0x000000000000738b <+37>:   mov    %rdx,-0x18(%rbp)
0x000000000000738f <+41>:   mov    -0x30(%rbp),%rax
0x0000000000007393 <+45>:   mov    %rax,%rsi
0x0000000000007396 <+48>:   lea    0x275ab(%rip),%rdi        # 0x2e948
0x000000000000739d <+55>:   mov    $0x0,%eax
0x00000000000073a2 <+60>:   callq  0x5570 <printf@plt>
0x00000000000073a7 <+65>:   mov    -0x28(%rbp),%rax
0x00000000000073ab <+69>:   mov    %rax,%rsi
0x00000000000073ae <+72>:   lea    0x275b3(%rip),%rdi        # 0x2e968
0x00000000000073b5 <+79>:   mov    $0x0,%eax
0x00000000000073ba <+84>:   callq  0x5570 <printf@plt>
0x00000000000073bf <+89>:   mov    -0x20(%rbp),%rax
0x00000000000073c3 <+93>:   mov    %rax,%rsi
0x00000000000073c6 <+96>:   lea    0x275c3(%rip),%rdi        # 0x2e990
0x00000000000073cd <+103>:  mov    $0x0,%eax
0x00000000000073d2 <+108>:  callq  0x5570 <printf@plt>
0x00000000000073d7 <+113>:  mov    -0x18(%rbp),%rax
0x00000000000073db <+117>:  mov    %rax,%rsi
0x00000000000073de <+120>:  lea    0x275e3(%rip),%rdi        # 0x2e9c8
0x00000000000073e5 <+127>:  mov    $0x0,%eax
0x00000000000073ea <+132>:  callq  0x5570 <printf@plt>
0x00000000000073ef <+137>:  nop
0x00000000000073f0 <+138>:  mov    -0x8(%rbp),%rbx
0x00000000000073f4 <+142>:  leaveq 
0x00000000000073f5 <+143>:  retq   
End of assembler dump.
(gdb)

Upvotes: 3

Views: 1663

Answers (2)

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215327

The problem is not that you read rsp. It's that you clobbered rbp (by overwriting it with the value copied from rsp) and rsp (by performing a push without a matching pop) from the asm block without informing the compiler about the clobbers. The former you could do by adding rbp to the clobber list; the latter is not legal at all.

Upvotes: 2

There's nothing that guarantees that the compiler you're compiling the code with is using those registers the way you imply it's using them. That's all there's to it. I'm not sure where you got the idea that it should be the way you imply without actually looking at the assembly output generated by the compiler as used to build your program.

When you're writing in assembly, you're interfacing with all the surrounding assembly code, so I'm befuddled why you'd do it in the dark. The first thing you have to do is to stop and figure out how to get assembly output from the compiler i.e. how to pass the options the compiler expects to save such assembly output to a file in addition to saving the object code into a file. Then rebuild your program and see how your assembly fits with the rest of it. Hint: it doesn't :)

If figuring this out on your own system is a bit too much distraction at the moment, then you can use https://godbolt.org to write your code, choose one of the gcc compilers, and then you can both examine the assembly output and run the program in the cloud and observe the effects. All you need for that is a web browser. Nothing else needs to be locally installed.

Upvotes: 2

Related Questions