如何以x86(AT&T语法)将字符串推入堆栈中

问题描述 投票:2回答:2

在x86 AT&T语法中,如何将ASCII字符串推入堆栈? (或者C程序如何将ASCII字符串推入堆栈?)

我的最初尝试是创建数据节,使用.asciz,然后使用LEA和MOV使用置换来推送内容。但这一切最终都出错了。

x86 att
2个回答
0
投票

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。)


-1
投票

这是我写的教程中的内容,您只需要定义字符串,然后将字符串移动到堆栈中即可。实际上,它仅移动起始地址,然后在要打印时指定偏移量的长度。

© www.soinside.com 2019 - 2024. All rights reserved.