x86_64 通过将函数参数存放在栈中的方式来实现参数传递。
# PURPOSE: Program to illustrate how functions work
# This program will compute the value of
# 2^3 + 5^2
#
# Everything in the main program is stored in registers,
# so the data section doesn’t have anything.
.section .data
.section .text
.globl _start
_start:
push $3 # 将第二个参数入栈
push $2 # 将第一个参数入栈
call power # 调用函数power,call会自动将函数返回地址入栈,
# 也就是下一条指令的地址
add $16, %rsp # move the stack pointer back,
# 通过移动栈顶指针的方式将保存在栈中的数据清理掉
push %rax # save the first answer before
# calling the next function
push $2 # push second argument
push $5 # push first argument
call power # call the function
add $16, %rsp # move the stack pointer back
pop %rbx # The second answer is already
# in %rax. We saved the
# first answer onto the stack,
# so now we can just pop it
# out into %rbx,将第二次计算的结果从栈中弹出存放到rbx寄存器中
add %rax, %rbx # add them together
# the result is in %rbx
mov $1, %rax # exit (%rbx is returned)
int $0x80
# PURPOSE: This function is used to compute
# the value of a number raised to
# a power.
#
# INPUT: First argument - the base number
# Second argument - the power to
# raise it to
#
# OUTPUT: Will give the result as a return value
#
# NOTES: The power must be 1 or greater
#
# VARIABLES:
# %rbx - holds the base number
# %rcx - holds the power
#
# -8(%rbp) - 将计算后的结果放在栈中
#
# %rax is used for temporary storage
#
.type power, @function
power:
push %rbp # 将旧的栈基址入栈
mov %rsp, %rbp # 当前rsp指向旧的栈基址,获取传入参数时需要加上返回地址和旧栈基址的偏移
# 因为存在两次入栈,一次是返回地址入栈,一次是rpb指针入栈
sub $8, %rsp # 在栈中申请8字节用于存放计算结果的内存
mov 16(%rbp), %rbx # 获取栈中传入的第一个参数,值存放在rbx
mov 24(%rbp), %rcx # 获取栈中传入的第一个参数,值存放在rcx
mov %rbx, -8(%rbp) # store current result
power_loop_start:
cmp $1, %rcx # if the power is 1, we are done
je end_power
mov -8(%rbp), %rax # move the current result into %eax
imul %rbx, %rax # multiply the current result by
# the base number
mov %rax, -8(%rbp) # 将计算结果更新到栈中
dec %rcx # decrease the power
jmp power_loop_start # run for the next power
end_power:
mov -8(%rbp), %rax # return value goes in %rax
mov %rbp, %rsp # restore the stack pointer
pop %rbp # restore the base pointer
ret
编译方式:as w_power.s -o w_power.o;ld w_power.o -o w_power
结果查看:执行w_power之后,echo $?查看计算结果。
使用专用寄存器来传递函数调用参数,rdi用来存放第一参数,rsi用来存放第二个参数,并且把第一计算的结果存放在栈中。
# PURPOSE: Program to illustrate how functions work
# This program will compute the value of
# 2^3 + 5^2
#
# Everything in the main program is stored in registers,
# so the data section doesn’t have anything.
.section .data
.section .text
.globl _start
_start:
mov $2, %rdi # 将第一个参数存入rdi
mov $3, %rsi # 将第二个参数存入rsi
call power # 调用函数power,call会自动将函数返回地址入栈,
# 也就是下一条指令的地址
push %rax # 将第一次计算的结果存放在栈中
mov $5, %rdi # 将第一个参数存入rdi
mov $2, %rsi # 将第一个参数存入rsi
call power
pop %rbx # 获取第一次的计算结果
add %rax, %rbx # 第一次计算结果rbx与第二次计算结果rax的值相加
# the result is in %rbx
mov $1, %rax # exit (%rbx is returned)
int $0x80
# PURPOSE: This function is used to compute
# the value of a number raised to
# a power.
#
# INPUT: First argument - the base number
# Second argument - the power to
# raise it to
#
# OUTPUT: Will give the result as a return value
#
# NOTES: The power must be 1 or greater
#
# VARIABLES:
# %rdi - 第一个参数
# %rsi - 第二个参数
#
# -8(%rbp) - 将计算后的结果放在栈中
#
# %rax is used for temporary storage
#
.type power, @function
power:
push %rbp # 将旧的栈基址入栈
mov %rsp, %rbp # 当前rsp指向旧的栈基址,获取传入参数时需要加上返回地址和旧栈基址的偏移
# 因为存在两次入栈,一次是返回地址入栈,一次是rpb指针入栈
sub $8, %rsp # 在栈中申请8字节用于存放计算结果的内存
mov %rdi, -8(%rbp) # store current result
power_loop_start:
cmp $1, %rsi # if the power is 1, we are done
je end_power
mov -8(%rbp), %rax # move the current result into %eax
imul %rdi, %rax # multiply the current result by
# the base number
mov %rax, -8(%rbp) # 将计算结果更新到栈中
dec %rsi # decrease the power
jmp power_loop_start # run for the next power
end_power:
mov -8(%rbp), %rax # return value goes in %rax
mov %rbp, %rsp # restore the stack pointer
pop %rbp # restore the base pointer
ret