将值从寄存器复制到变量 x86-64 时出现问题

Problem copying value from register to variable x86-64

提问人:Charlie Benger-Stevenson 提问时间:11/8/2023 最后编辑:Peter CordesCharlie Benger-Stevenson 更新时间:11/8/2023 访问量:41

问:

我正在尝试将传递给我的简单汇编语言程序的命令行参数存储在变量中以供以后使用。

global _start
    
section .text

_start:
    pop rax       ; argc
    cmp rax,1     ; no command line arguments supplied
    jz  begin
get_cmdln_args: 
    pop rax       ; argv
    pop rax       ; arg[1]
    cmp byte [rax], '-'; test string first char for - character
    jz  parse_option  ;
    pop rax       ; arg[2]
    pop rax       ; arg[3]
parse_option:
    cmp byte [rax +1], 'p'
    jz portarg
portarg:
    pop rax
    mov [port], rax
portargl:   
    cmp byte [rax], $0
    jz get_cmdln_args
    inc rax
    jnz portargl
begin:  
    mov rax, 1        ; write(
    mov rdi, 1        ;   STDOUT_FILENO,
    mov rsi, msg      ;   "Hello, world!\n",
    mov rdx, msglen   ;   sizeof("Hello, world!\n")
    syscall           ; );

    mov rax, 60       ; exit(
    mov rdi, 0        ;   EXIT_SUCCESS
    syscall           ; );

section .bss
  port: resb 8
    
section .rodata
  msg: db "Hello, I am from the Isle of Mann!", 10
  msglen: equ $ - msg

问题出在 portarg 标签上。

在 GDB 中,我可以看到 RAX 的值是“8080”,这是在命令行上指定的值,因此

gdb --args hello -port 8080

启动调试器,我可以看到堆栈上的命令行参数。 弹出堆栈后,我可以看到 RAX 中的命令行参数。

执行 mov 指令后,我仍然可以在 RAX 中看到“8080”,但存储在我的变量中的内容看起来很可疑。

变量的地址为 0x403024

x/s 0x403024

返回

"\222\342\377\377\377\177"

这是怎么回事?

我怎样才能在这个地址将其存储为整数?我见过你这样做的例子

子 RAX, '0'

删除尾随的 0,然后将其视为整数。如果我在这里尝试,我会得到一个空字符串。

程序集 x86-64

评论


答:

1赞 Melvin 11/8/2023 #1

误解是您试图将命令行参数作为整数存储在内存中。然而,如果你使用'pop rax',它是由一个字符串表示的。解决方案相当简单:您需要手动将字符串转换为整数。确保将计算值另存为四字字。基本例程可能如下所示:

str_to_int:
    ; Convert a null-terminated string in rdi to an integer in rax
    xor rax, rax          ; Clear rax to store the result
    xor rcx, rcx          ; Clear rcx to use as a counter

convert_loop:
    movzx rbx, byte [rdi + rcx]  ; Load the next character
    test rbx, rbx                 ; Check if it's the null terminator
    jz done_conversion            ; If it is, we are done

    sub rbx, '0'                  ; Convert ASCII to integer
    imul rax, rax, 10            ; Multiply current result by 10
    add rax, rbx                 ; Add the new digit
    inc rcx                      ; Move to the next character
    jmp convert_loop

done_conversion:
    ret

评论

2赞 Peter Cordes 11/8/2023
RBX 在标准调用约定中保留调用;你可以在那里使用 RDX。例如 / 将零扩展到 RDX 并递增指针。(不需要单独的寄存器索引)。NASM 程序集将输入转换为整数?显示此循环的一个版本,条件分支位于底部,以第一个非数字字符结尾。movzx edx, byte [rdi]inc rdi