首页 > 解决方案 > 移动一行代码会以某种方式改变我的 x86-64 GNU 汇编程序的寄存器值

问题描述

环境和工具:

问题:在汇编程序的源代码中移动一行代码会以某种方式更改寄存器的值,从而使程序的输出不正确

预期输出:程序将返回 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

标签: linux64-bitattgnu-assembler

解决方案


推荐阅读