I want to call a write syscall from 32-bit assembly, the code i'm using right now:
.section .rodata # read-only data
msg:
.ascii "hello" # char array called "msg" (no null character)
len:
.long 5 # length of "msg"
.section .text # actual runnable code
.globl _start
.type _start, @function
_start:
movl $4, %eax # syscall number into eax (4 is write)
movl $1, %ebx # argument number 1 into ebx (stdout)
movl $msg, %ecx # argument number 2 into ecx
movl len, %edx # argument number 3 into edx
int $0x80
movl $1, %eax # syscall number into eax (1 is exit)
movl $0, %ebx # argument number 1 into ebx (exit code)
int $0x80
To compile it i first invoke the GNU assembler and then the linker:
as --32 main.s -o main.o
ld -m elf_i386 main.o -o main
It compiles and works properly, printing the string "hello" to the console, but when i use strace to "see" the write happen, i get following output:
execve("./main", ["./main"], [/* 86 vars */]) = 0
strace: [ Process PID=22529 runs in 32 bit mode. ]
write(1, "hello", 5hello) = 5
exit(0) = ?
+++ exited with 0 +++
I'd like to know what causes the third argument to be 5hello instead of 5.
Nothing, the hello
in there is the actual output of your program. Here is what is happening:
write(1, "hello", 5
. Note this goes to stderr
. For some reason it doesn't print the closing )
yet.write
syscall gets executed, thus hello
is printed to stdout
.) = 5
.In your case both stdout
and stderr
refer to the same terminal. Redirect the output of either strace or your code so they don't get interspersed.