简体   繁体   中英

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

In x86 AT&T synatax, how does one push an ASCII string into a stack? (Or how does a C program push an ASCII string into a stack?)

My intial attempt was to create data section, use .asciz and then push things using LEA and MOV using displacement. But it all ended up with errors.

C programs don't push strings, they push pointers to strings.

Asm programs can push variable-length things onto the stack, but it's weird and rarely useful. When optimizing your code, only consider it after considering the normal way.

It could certainly be useful for allocating space for a variable-sized input that's only available one byte at a time, like reading input. (Like a local variable-sized array, except you grow it as you read input, instead of having to choose a size before you're done reading.)

Anyway, the normal way (pushing a pointer) looks like this:

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!"

Note that I used const char str[] instead of const char *str so the symbol address would be the string-constant's address, rather than the address of a pointer. Using const char *str results in a load (pushing contents of memory), instead of a push-immediate, to set up the args for foo. Using static const char *str lets the compiler resolve the indirection at compile time, and push $.LC0, %edi , never bothering to put a pointer to .LC0 in the .rodata section.

In 64bit mode, compiling with -fPIC will force the compiler to use a RIP-relative lea instead of a mov-immediate. In 32bit code -fPIC , generate some really clunky stuff to get the current value of EIP and find the symbol address in the Global Offset Table.

I made hello return 0 instead of also being void, so I didn't have to explain tail-call optimization ( jmp instead of call ). (Which doesn't happen in 32bit mode because the caller has to pop the arg after foo returns. When I first wrote this answer, I forgot that the question was about the stack, rather than just passing strings to functions. The 64bit ABI passes args in registers.)

This is from a tutorial I wrote, you just need to define your string and then mov the string to the stack. In reality it is moving only the start address, then when you want to print you specify the length for the offset.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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