繁体   English   中英

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

[英]how to push a string into a stack in x86 (AT&T syntax)

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

我最初的尝试是创建数据部分,使用 .asciz,然后使用 LEA 和 MOV 使用位移推送东西。 但这一切都以错误告终。

C 程序不推送字符串,它们推送指向字符串的指针。

Asm 程序可以将可变长度的东西压入堆栈,但它很奇怪而且很少有用。 在优化你的代码时,只有考虑正常方式后才考虑它。

它对于为一次只能使用一个字节的可变大小输入分配空间当然很有用,例如读取输入。 (就像一个局部可变大小的数组,除了你在读取输入时增长它,而不是在你完成读取之前选择一个大小。)

无论如何,正常的方式(推送一个指针)是这样的:

static const char str[] = "Hello World!";
void foo(const char*p);
int hello(void) { 
  foo(str);
  return 0;
}

并编译为以下 32 位代码(其中调用约定使用堆栈)

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, %edipush $.LC0, %edi ,而.LC0在 .rodata 部分放置指向.LC0的指针。

在 64 位模式下,使用-fPIC进行编译将强制编译器使用 RIP 相关的lea而不是 mov-immediate。 在 32 位代码-fPIC ,生成一些非常笨重的东西来获取 EIP 的当前值并在全局偏移表中找到符号地址。

我让hello返回 0 而不是 void,所以我不必解释尾调用优化( jmp而不是call )。 (这在 32 位模式下不会发生,因为调用者必须在 foo 返回后弹出 arg。当我第一次写这个答案时,我忘记了问题是关于堆栈的,而不仅仅是将字符串传递给函数。64 位 ABI 通过寄存器中的参数。)

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

Compiling assembler: nasm -felf64 "helloworld.asm"...
Linking object helloworld.o: ld -melf_x86_64 -o helloworld helloworld.o ...
Displaying helloworld.asm asm source: 
section     .text
global      _start                              ;must be declared for linker (ld)

_start:                                         ;tell linker entry point

    mov     rdx,len                             ;message length
    mov     rcx,msg                             ;message to write
    mov     rbx,1                               ;file descriptor (stdout)
    mov     rax,4                               ;system call number (sys_write)
    int     0x80                                ;call kernel

    mov     rax,1                               ;system call number (sys_exit)
    int     0x80                                ;call kernel

section     .data

msg     db  'Hello, world!',0xa                 ;our dear string
len     equ $ - msg                             ;length of our dear string

Executing linked helloworld executable! ./helloworld | figlet ..
 _   _      _ _                             _     _ _ 
| | | | ___| | | ___    __      _____  _ __| | __| | |
| |_| |/ _ \ | |/ _ \   \ \ /\ / / _ \| '__| |/ _` | |
|  _  |  __/ | | (_) |   \ V  V / (_) | |  | | (_| |_|
|_| |_|\___|_|_|\___( )   \_/\_/ \___/|_|  |_|\__,_(_)
                    |/                                
./helloworld: ELF 64-bit LSB  executable, x86-64, version 1 (SYSV), statically linked, not stripped

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM