如何在 ASMx64 中多次取消引用指针?

How to dereference a pointer multiple times in ASMx64?

一切都在标题中,我有一个 int** 作为我的函数参数,我想用汇编显示 int,所以我所做的是:

global bar

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

我的C代码:

#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);
}

使用 lldb 在 foo 处出现段错误并显示“无效地址”,所以我认为这是因为我没有以正确的方式取消引用,所以我被卡住了,因为我需要为更大的对象执行此操作功能。感谢您的帮助。

让我跟踪汇编代码:

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

这表明实际上您必须传递 int****,而不是 int** 作为第一个参数,因为您正在执行 4 次取消引用。

会变成这样:

#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);
}

此外,在 x86-64 中调用函数时堆栈指针应为 16 字节对齐,因此汇编函数 bar 应为(例如):

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

对齐在call之前完成,8字节(return地址)被call压入,所以函数指针要减去另外8字节保留16-字节对齐。

如果你想使用 int** 作为第一个参数,只进行 2 次解引用(内存访问)。

global bar

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

您可能想做的另一件事是

  1. 创建栈帧
  2. 将参数存储在堆栈内存中以备后用
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

我想你可能想要这个:

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

这将匹配 void bar(int **i, void (*f)()) 原型