4

I have just started to teach myself x86 assembly on linux from these video tutorials. Early on it teaches you how to use the write sys-call to print a string that is stored in the data section. Is it possible to use the write syscall to print a string that is stored on the stack. Here is the code I wrote to try and do this which doesn't seem to work.

.data
abc: 
    .asciz "ABC"
.text
    .globl _start

_start:
    pushq %rbp
    movq %rsp, %rbp
    subq $32, %rsp
    leaq -32(%rbp), %rdi
    movb $65, (%rdi)        #move 'A' on to stack
    addq $1, %rdi           
    movb $66, (%rdi)        #move 'B' on to stack
    addq $1, %rdi
    movb $67, (%rdi)        #move 'C' on to stack
    addq $1, %rdi
    movb $0, (%rdi)         #Null terminate  

    movq $4, %rax           #4 is write syscall
    movq $1, %rbx           #1 for stdout
    movq %rsp, %rcx         #pointer to ABC string on stack
    movq $3, %rdx           #length of string
    int $0x80

    movq $1, %rax           #exit syscall
    xorq %rbx, %rbx
    int $0x80

This program just runs and exits without printing ABC, but if I pass the string stored in the data segment, ABC is printed. Am I doing something wrong or can you not do it this way. Any help apprecitated.

2
  • Except for the initial pushq, this code never appears to modify the stack pointer... Did you mean 'subq $32, %rsp', or am I missing something? Commented Jul 17, 2011 at 13:40
  • @Nemo I did yeah, that's just a typo in my post. I do it correctly in my original code. Thanks Commented Jul 17, 2011 at 13:43

1 Answer 1

4

Your syscall numbers seem WAY off.

From your use of movq and the "r" registers, I can guess you are trying on x86-64. Taking a look at /usr/include/asm/unistd_64.h, I can see the following:

#define __NR_write                              1
#define __NR_stat                               4
#define __NR_exit                               60

strace agrees with me:

$ strace ./abc
execve("./abc", ["./abc"], [/* 43 vars */]) = 0
stat("", NULL)                          = -1 EFAULT (Bad address)
write(-1698988341, NULL, 3 <unfinished ... exit status 0>

Note that the parameters are also way off. You are also using the wrong registers for the rest of the parameters. The calling convention on x86-64, AFAIK, uses the following registers for the parameters, in this order: rdi, rsi, rdx, r10, r8, r9.

Perhaps you are trying to do syscalls on x86-64 the way they are done on i386 and expecting it to be the same?

Sign up to request clarification or add additional context in comments.

8 Comments

int $0x80 isn't the syscall gate on x86-64 either...
Another related question: stackoverflow.com/questions/1204026/…
Thank you. I never suspected it'd be a 64bit issue. I changed the syscall number and googled for the the correct registers for the parameters and it works now. It is strange though why the 32bit syscall procedure works with the string in the data segment.
@bdonlan, this seems very logical. I ran my program in gdb and the stack address was a value greater than 2**32, where as the data segment naturally was a low address. Thanks for all your help everyone. :)
|