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.
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
.