linux - 移动一行代码会以某种方式改变我的 x86-64 GNU 汇编程序的寄存器值
问题描述
环境和工具:
- Ubuntu Linux
- GNU 汇编器(用于 Ubuntu 的 GNU Binutils)2.34
- GNU ld(用于 Ubuntu 的 GNU Binutils)2.34
问题:在汇编程序的源代码中移动一行代码会以某种方式更改寄存器的值,从而使程序的输出不正确
预期输出:程序将返回 5 (120) 的阶乘作为退出代码
实际输出:退出代码为 16
问题代码片段:
// n! = n * (n - 1)!
dec %rax # decrement the value of %rax by 1
push %rax # then call factorial with it
call factorial # the value returned by the function will be stored in %rax
mov 16(%rbp), %rbx # copy the input to %rbx, this is the offending line
imul %rbx, %rax # multiply the input to the result of factorial of (input - 1)
上面的代码可以正常工作,但是一旦我移动mov 16(%rbp), %rbx
,之前call factorial
的任何地方,结果都会以某种方式改变。
如果您有兴趣,下面是完整的代码:
# PURPOSE: Get the factorial of a given number
# INPUT: Hardcoded values (non-negative and non-zero)
# OUTPUT: The value will be return as the program's exit code (0-255 only)
# Use `echo $?` to get the exit code on a linux machine
.section .data
.section .rodata
input: .8byte 5
.section .text
.globl _start
_start:
# push the parameters in reverse order and call the function
push input # push input as the first argument
call factorial # assign the address of the function to %rip (instruction pointer)
# and pushes the return address of the called function
add $8, %rsp # clean the stack
# exit the program
mov %rax, %rdi # set the return of the function as the exit code
mov $60, %rax # set 60 (exit) as the system call number to %rax
syscall # switch to kernel mode
/*
* Computes the factorial of a number through recursion
*
* Parameters:
* param1 - the number to get the factorial of
*
* Return: the result of the factorial (stored in %rax)
*/
.type factorial, @function
factorial:
# create the stack frame
push %rbp # push the current base pointer register
mov %rsp, %rbp # assign the value of stack pointer register
# as the new value of the base pointer register
# we will use the base pointer to access the return address,
# local variables, and parameters
# copy the input to %rbx
mov 16(%rbp), %rax # copy input to %rax
# if the input is less than or equals to 1 then we're done
cmp $1, %rax
jle return_factorial
// n! = n * (n - 1)!
dec %rax # decrement the value of %rax by 1
push %rax # then call factorial with it
call factorial # the value returned by the function will be stored in %rax
mov 16(%rbp), %rbx # copy the input to %rbx
imul %rbx, %rax # multiply the input to the result of factorial of (input - 1)
return_factorial:
mov %rbp, %rsp # reset the %rsp back to its original value before the call
pop %rbp # reset the %rbp back to its original value before the call
ret # this is equivalent to doing pop %rip
解决方案
推荐阅读
- css - 将已编译的 scss 添加到 gitignore 但不添加源 css 文件
- python - 如果 CPU 和 RAM 已用尽,多处理和多线程的组合在 python 中是否有用?
- ios - 已批准的 iOS 应用内购买是否可用于后置应用版本?
- python - 用 scatter_density 叠加图
- postgresql - linux容器postgres密码认证失败
- sql-server - Microsoft SQL Server Docker Compose --> 加载现有数据库
- android - Airship 深层链接通知正在启动应用程序,但意图中没有数据
- c# - Avaya Auto Dialer Moagent 开发环境
- docker - Docker compose - 限制互联网访问,只允许通过代理出口
- sql - 使用存储过程将文件 URL 转换为文件字节?