程序集,x86:如何将标签推送到堆栈?

Assembly, x86: How to push a label to the stack?

给定数据:

.section data
data_set:
.long 2,5,33,54,2,76,4,37,43,223,98,70,255

如何将数据的起始地址(而不是该地址中的值)压入堆栈?

我试过这个:

pushl data_set

最终(在尝试访问该地址中的数据之后)导致了段错误。

在 AT&T 语法中,要将地址用作指令的直接操作数,请使用 $label

你想要 pushl $data_set 用于 push imm32 指令。,就像你 push 3.

pushl data_set 将推送从地址 data_set 加载的双字数据,即
push m32.


从概念上讲,AT&T 语法将所有内容都视为潜在地址。所以label是地址,0x123也是地址。因此 add 0x123, %eax 从地址 0x123 加载,而 add label, %eax 从地址 label 加载。当你想要一个数字作为立即操作数时,你可以使用 add [=24=]x123, %eax。使用符号地址作为立即操作数的工作方式相同。

无论哪种方式,地址都编码到指令中,只是寻址方式中是立即数还是位移的问题。这就是你使用
的原因 add $(foo - bar), %eax 添加两个符号之间的距离,而不是
add $foo-$bar, %eax(它会寻找一个名为 $bar 的符号,即 $ 是符号名称的一部分)。 $ 适用于整个操作数,不适用于符号/标签名称。相关:more about assemble-time math in GAS

在其他情况下,例如作为 .long.quad 的操作数,不存在直接与内存操作数的问题,因此您只需编写 dataptr: .long data_set 即可发出 4 个字节的数据,其中包含 data_set 的地址,就像你从 C static int *dataptr = data_set;

得到的一样

您可以通过查看

的 C 编译器输出来检查语法
void ext(int*);
static int data[] = {1,2,3};
void foo() {
    ext(data);
}

让 C 编译器生成将符号地址传递给函数的代码。我把它放在 the Godbolt compiler explorer 上,它确实使用了 pushl $data.