在x86 AT&T语法中,如何将ASCII字符串推入堆栈? (或者C程序如何将ASCII字符串推入堆栈?)
我的最初尝试是创建数据节,使用.asciz,然后使用LEA和MOV使用置换来推送内容。但这一切最终都出错了。
C程序不推字符串,它们推指针到字符串。
Asm程序可以将可变长度的东西压入堆栈,但这很奇怪,很少有用。优化代码时,仅考虑after考虑常规方法即可。
对于为每次只能使用一个字节的可变大小的输入分配空间,例如读取输入,这肯定是有用的。 (就像本地可变大小的数组一样,除了在读取输入时增大它,而不必在完成读取之前选择大小。)
无论如何,正常方式(按下指针)如下所示:
static const char str[] = "Hello World!";
void foo(const char*p);
int hello(void) {
foo(str);
return 0;
}
and compiles to the following 32bit code (where the calling convention uses the stack)
hello:
subl $24, %esp # keep the stack aligned for foo()
pushl $str # push-immediate with the address of the string
call foo
xorl %eax, %eax # return value
addl $28, %esp # pop the arg and the padding
ret
.section .rodata
.align 8
str:
.string "Hello World!"
请注意,我使用const char str[]
而不是const char *str
,因此符号地址将是字符串常量的地址,而不是指针的地址。使用const char *str
会导致加载(推送内存内容),而不是立即发送,从而为foo设置了args。使用static const char *str
可以使编译器在编译时解析间接寻址,而push $.LC0, %edi
则可以使用.rodata节中的.LC0
指针。
在64位模式下,使用-fPIC
进行编译将强制编译器使用相对于RIP的lea
而不是mov-immediate。在32位代码-fPIC
中,生成一些笨拙的东西以获取EIP的当前值并在全局偏移表中找到符号地址。
[我使hello
返回0而不是也为空,所以我不必解释尾部调用优化(jmp
而不是call
)。 (在32位模式下不会发生这种情况,因为调用者必须在foo返回后弹出arg。当我第一次编写此答案时,我忘记了问题是关于堆栈的,而不仅仅是将字符串传递给函数。64位ABI通过寄存器中的args。)
这是我写的教程中的内容,您只需要定义字符串,然后将字符串移动到堆栈中即可。实际上,它仅移动起始地址,然后在要打印时指定偏移量的长度。