Deathsbreed Deathsbreed - 1 year ago 93
Linux Question

Assembly x86-64 get function parameters from stack

Lately I've been learning x86 Assembly from the book Programming from the Ground Up, but I have an x86-64 computer, so things start to go wrong at one point (pretty early in the book). I got to the part where I'm dealing with functions, specifically the power example. In this example he pushes the parameters onto the stack and then copies them into registers later in the function. Here's what his code looks like:

pushl $3 # second argument
pushl $2 # first argument
call power # call function
pushl %ebp # save old base pointer
movl %esp, %ebp # make stack pointer the base pointer
subl $4, %esp # get room for our local storage

movl 8(%ebp), %ebx # put first argument in %eax
movl 12(%ebp), %ecx # put second argument in %ecx

Of course, this is 32-bit, and I'm running 64-bit, so I tried updating the registers and instruction suffixes to end up with something like this (comments shouldn't be needed this time):

pushq $3
pushq $2
call power
pushq %rbp
movq %rsp, %rbp
subq $4, %rsp

movq 8(%rbp), %rdi
movq 12(%rbp), %rsi

Given, I might just be confusing the actual registers I'm supposed to use, but I'm not completely sure. All I know is that when I print the value of %rdi in the GNU Debugger after the command
movq 8(%rbp), %rdi
it seems to me as if it has the memory address rather than the contents of it considering I get the following:

(gdb) i r rdi
rdi 0x400081 4194433

Also, is there something like a forum for Assembly hobbyists? I've done some basic searching but haven't managed to find one (except for a forum for x86 assembly that just has one post and it's a welcome post,


Answer Source

The standard 64 bit conventions don't use the stack like that, they pass at least the first few arguments (type permitting) in registers. Of course for your own code you can still use the stack. However, you should adjust your offsets so that they use the appropriate size, 8 bytes instead of 4.

subq $4, %rsp

You should really use multiples of 8 unless you know what you are doing.

movq 8(%rbp), %rdi

You expect this to be the first argument but it isn't. It is actually the return address on the stack, since each item is 8 bytes now. So at 0(%rbp) you have the pushed rbp, and 8(%rbp) is the return address. Thus 16(%rbp) is the first argument and 24(%rbp) is the second.

Note that in most environments you can still write 32 bit code, so if you want to keep using that book you might want to do that instead of trying to adjust for 64 bit.

PS: You get a cookie for using a debugger :)

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download