Fayeure
Fayeure

Reputation: 1369

How to dereference a pointer multiple times in ASMx64?

All is in the title, I have an int** as my function argument and I want to display the int with assembly, so what i've done is:

global bar

section .text:
bar:
  mov  rdx, [rdi]
  mov  rdi, [rdx]
  mov  rdx, [rdi]
  mov  rdi, [rdx]
  call rsi
  ret

My C code:

#include <stdio.h>

void  bar(int **i, void (*f)());  //assembly function prototype

void  foo(int i)
{
  printf("%d\n", i);
}

int   main(void)
{
  int i = 3;
  int *ptr = &i;

  bar(&ptr, &foo);
  return (0);
}

It segfaults and says "invalid address" at foo with lldb, so I think it's because i'm not dereferencing the right way, so I'm stuck because I need to do this for a larger function. Thanks for the help.

Upvotes: 1

Views: 661

Answers (2)

MikeCAT
MikeCAT

Reputation: 75062

Let me trace the assembly code:

global bar

section .text:
bar:
  mov  rdx, [rdi] // rdi = &ptr, rdx = *&ptr = ptr
  mov  rdi, [rdx] // rdx = ptr, rdi = *ptr = i
  mov  rdx, [rdi] // rdi = i, rdx = *i = (invalid)
  mov  rdi, [rdx]
  call rsi
  ret

This suggests actually you have to pass int****, not int**, as the first argument because you are doing dereference 4 times.

It will be like this:

#include <stdio.h>

void  bar(int ****i, void (*f)());  //assembly function prototype

void  foo(int i)
{
  printf("%d\n", i);
}

int   main(void)
{
  int i = 3;
  int *ptr = &i;
  int **pptr = &ptr;
  int ***ppptr = &pptr;

  bar(&ppptr, &foo);
  return (0);
}

Also stack pointer should be 16-byte aligned on function call in x86-64, so the assembly function bar should be (for example):

global bar

section .text:
bar:
  mov  rdx, [rdi]
  mov  rdi, [rdx]
  mov  rdx, [rdi]
  mov  rdi, [rdx]
  sub  rsp, 8 // adjust stack pointer
  call rsi
  add  rsp, 8 // restore stack pointer
  ret

The alignment is done before call and 8 byte (return address) is pushed by call, so another 8 byte should be subtracted from the function pointer to retain 16-byte alignment.

If you want to use int** as the first argument, do dereferences (memory accesses) only 2 times.

global bar

section .text:
bar:
  mov  rdx, [rdi]
  mov  rdi, [rdx]
  sub  rsp, 8
  call rsi
  add  rsp, 8
  ret

Another thing you may want to do is

  1. Create stack frame
  2. Store the argument on the stack memory for later use
global bar

section .text:
bar:
  push rbp // create stack frame
  mov  rbp, rsp
  sub  rsp, 16 // create region for local variables (note 16-byte alignment)
  mov  [rbp-8], rdi // save the argument to the memory
  mov  rdx, [rdi]
  mov  rdi, [rdx]
  mov  rdi, [rbp-8] // restore the argument from the memory
  mov  rdx, [rdi]
  mov  rdi, [rdx]
  call rsi
  leave // destruct stack frame
  ret

Upvotes: 4

Jabberwocky
Jabberwocky

Reputation: 50831

I think you might want this:

bar:
   mov   rax, [rdi]
   mov   edi, [rax]
   call  rsi
   ret

which would match the void bar(int **i, void (*f)()) prototype

Upvotes: 2

Related Questions