在递归函数中使用 pushad 时,堆栈指针似乎没有增加

Stack pointer does not seem to increase when using pushad in recursive function

int x = 5;

void foo()
{
  long unsigned r[8];
  memset(&r, 0, sizeof(long unsigned) * 8);

  __asm {

    pushad;

    pop r[7];
    pop r[6];
    pop r[5];
    pop r[4];
    pop r[3];
    pop r[2];
    pop r[1];
    pop r[0];
  }

  printf("Register values: \n");

  printf("eax: %lu\n", r[0]);
  printf("ecx: %lu\n", r[1]);
  printf("edx: %lu\n", r[2]);
  printf("ebx: %lu\n", r[3]);
  printf("esp: %lu\n", r[4]);
  printf("ebp: %lu\n", r[5]);
  printf("esi: %lu\n", r[6]);
  printf("edi: %lu\n", r[7]);

  if (--x) { foo(); }
}

int main()
{
  foo();
  return 0;
}

我刚刚了解了 pushad/pusha 操作,正在尝试查看 GPR 的变化情况。但是,除了 r[0] 之外,我似乎得到了所有这些的 0 打印,它为每个 foo() 调用打印出按 44 递减的数字。对吗?

据我所知,每次调用新函数时 esp 寄存器不应该移动吗?

这并不完全符合您的要求:

pop r[7];
pop r[6];
pop r[5];
pop r[4];
pop r[3];
pop r[2];
pop r[1];
pop r[0];

这实际上并没有计算数组中每个 LONG 的地址 r 并将值弹出到该位置。就像写:

pop [r+7];
pop [r+6];
pop [r+5];
pop [r+4];
pop [r+3];
pop [r+2];
pop [r+1];
pop [r+0];

内联程序集不考虑数组数据元素的大小。将值添加到数组的基数递增,就像索引以字节为单位一样。

可能更清楚发生了什么。 r 将是数组的基地址(因为它在堆栈上,所以相对于 ebp)。 r+0 是第一个 BYTE 的位置,r+1 是第二个 BYTE 的位置等。您需要计算并计算每个 LONG 的索引。所以它应该看起来像:

pop r[28];
pop r[24];
pop r[20];
pop r[16];
pop r[12];
pop r[8];
pop r[4];
pop r[0];