Search code examples
assemblyx86libccalling-conventiongnu-assembler

Stack arguments are disappearing in assembly using C calling convention


I am currently writing a bit of x86 assembly code and linking it with glibc using as and ld.

    .section .data

str1:
    .asciz "\n"

str3:
    .asciz "Hello"

str4:
    .asciz "Goodbye"

str5:
    .asciz "Guten Tag!"

str6:
    .asciz "Guten Morgen!"


    .section .bss
    .section .text
    .globl _start

_start:
    call main
    movl %eax, %ebx
    movl $1, %eax
    int $0x80

# void writeLine(char*);

    .type writeLine, @function
writeLine:
    pushl %ebp
    movl %esp, %ebp
    movl $str1, %ecx
    pushl %ecx
    movl 8(%ebp), %ecx
    pushl %ecx
    call strcat
    movl %eax, %ecx
    pushl %ecx
    call puts
    popl %ebx
    .leaver1:
    movl %ebp, %esp
    popl %ebp
    ret

    .type main, @function
main:
    pushl %ebp
    movl %esp, %ebp
    movl $str3, %ecx
    pushl %ecx
    call writeLine
    popl %ebx
    movl $str4, %ecx
    pushl %ecx
    call writeLine
    popl %ebx
    movl $str5, %ecx
    pushl %ecx
    call writeLine
    popl %ebx
    movl $str6, %ecx
    pushl %ecx
    call writeLine
    popl %ebx
    .leaver3:
    movl %ebp, %esp
    popl %ebp
    ret

The problem is, as apposed to the expected output:

Hello
Goodbye
Guten Tag!
Guten Morgen!

I get:

Hello
Guten Tag!

With some more in-depth debugging it would seem that the arguments are disappearing as when I do a printf like this:

pushl 8(%ebp)   # Argument for writeLine
pushl $str7     # "Argument for writeLine: %s\n"
call printf     # printf();

It shows the "disappearing" arguments as nothing, like:

# should be "Goodbye"
Argument for writeLine: 

As well when I print out the argument in the format %d I end up getting a constant number that changes only by what string (str3, str4, etc.) I'm passing.

Example: 134525414

I have also tried to compare it with the assembly generated by gcc (gcc -m32 -S main.c) from compiling a program that should do the exact same thing, and aside from the gcc-generated stuff I couldn't find anything with a swift look at the code.

So as it would seem, my arguments are disappearing.


Solution

  • strcat(str3, str1) concatenates str1 onto the end of str3 by copying the bytes of str1 into memory starting at the terminating null byte of str3. So the terminating null of str3 gets overwritten by the character '\n', and a new terminating null is written to the following byte. But guess what: the byte immediately following the terminating null of str3 is the first byte of str4. So you've just overwritten the first byte of str4 with a null byte. Hence it behaves like an empty string when you go to print it later.

    You could add an extra byte of space between each of your strings to avoid this. But more broadly, it isn't really sensible for a writeLine function to modify the string it is passed, so a better plan would be to redesign it so it doesn't need to do that. For instance, you could write the passed string with one call to puts (which already appends a newline), and if you want an additional newline, make a separate call to putc.