alexandernst
alexandernst

Reputation: 15099

Getting local var from caller function via EBP

I'm trying to get a local variable defined in the caller from the callee via EBP. It should be possible, but if it's not, please explain why.

This is the code I have right now:

#include <stdio.h>

void TEST(int a, int b, int c){
  int answer;
  printf("a: %d | b: %d | c: %d\n", a, b, c);

  __asm__ __volatile__(
    ".intel_syntax;"
    "mov %0, dword ptr ds:[ebp + 20];"        <-- EBP+20 == d == 42
    ".att_syntax;"
    : "=r" (answer)
    :
    :
  );

  printf("Answer: %d\n", answer);
}

int main(void){
  int a = 13;
  int b = 14;
  int c = 15;
  int d = 42;
  TEST(a, b, c);
}

By the time TEST gets called I expect the stack to look the following way:

|+20|  | 13     <-- d
|+16|  | 14     <-- c
|+12|  | 15     <-- b
|+ 8|  | 42     <-- a
|+ 4|  | return address
|  0|  | EBP
|- 4|  | local var answer
|- 8|  | ...

If I try to compile the following code I get:

test.c: Assembler messages:
test.c:7: Error: segment register name expected

Where is the error?

Upvotes: 1

Views: 303

Answers (2)

m3tikn0b
m3tikn0b

Reputation: 1318

I guess your example is for educational purposes only, so it's ok.

But generally be aware that you cannot rely on the order of variables on the stack. (You can't even rely on finding them on the stack).

For example if you make d an int d[1] = {42} several compilers will emit d,a,b,c instead of a,b,c,d. And if you turn on the optimizer everything can happen (and why would you use inline assembly mixed with unoptimized C code?).

See examples here.

Upvotes: 1

qwr
qwr

Reputation: 3670

move mem2,mem1

is not allowed.But this will be handled by gcc even on intel syntax. my assumtion was incorrect. Gcc will generate correct code for both intel and at&t syntax.

 "movl  mem1,%0"
        : "=r" (mem2) 

Gcc will generate valid code for us:

mov    mem1,%eax
 mov    %eax,mem2

Error: segment register name expected:

gcc cant get segment register name.But there is segment ds register.Plus it should be ok even without mentioning segment register.Actual problem was just prefix problem

Should be done: to solve this we have to use nonprefix or put prefixes %

The same Example :

Its on x64 machine. you should change rbp->ebp. and also 0x10 can be changed

#include <stdio.h>
#include <stdlib.h> 
 #include <stdint.h>
void TEST(int a, int b, int c) {
    int answer;

    int x = 16;


  __asm__ __volatile__(  
            ".intel_syntax noprefix ;"
            "mov %0, dword ptr   ds:[rbp + %1+0];"
  ".att_syntax;"
            : "=r" (answer) 
            : "r"((uintptr_t)x) /* x is input operand */
             );  
      printf("Answer: %d\n", answer);
    __asm__ __volatile__(  
   " movl    0(%%rbp,%1,1),%0"
            : "=r" (answer) 
            : "r"((uintptr_t)x) /* x is input operand */
             );  
      printf("Answer: %d\n", answer);
    __asm__ __volatile__(
            "movl  0x10(%%rbp),%0"
            : "=r" (answer)
            );
    printf("Answer: %d\n", answer);
    __asm__ __volatile__(
            ".intel_syntax;"
            "mov %0, dword ptr  [%%rbp + 0x10];"
            ".att_syntax;"
            : "=r" (answer)
            );
    printf("Answer: %d\n", answer);

    //the same as you wrote, just I added noprefix
    __asm__ __volatile__(
            ".intel_syntax noprefix ;"
            "mov %0, dword ptr   ds:[rbp + 0x10];"
            ".att_syntax;"
            : "=r" (answer)
            );
    printf("Answer: %d\n", answer);
    //this lines just to test if we refer the same address as address of d
    void *addressd;
    __asm__ __volatile__(
            "lea  0x10(%%rbp),%0"
            : "=r" (addressd)
            );
    printf("TEST: address of d %p\n", addressd);
}

int main(void) {
    int a = 13;
    int b = 14;
    int c = 15;
    int d = 42;
    TEST(a, b, c);
    printf("address of d %p", &d);
}

Upvotes: 1

Related Questions