【问题标题】:Displaying 64-bit register in ASM在 ASM 中显示 64 位寄存器
【发布时间】:2014-10-12 21:20:34
【问题描述】:

这是我第一次尝试在 Linux 下进行 64 位汇编。我正在使用 FASM。

我正在将 64 位寄存器十六进制值转换为字符串。它工作正常,直到达到最后一个数字。我无法弄清楚我的代码到底有什么问题。也许有一些关于 64 位编程的东西我不知道或与系统调用有关(我也是一个 linux 菜鸟)

format ELF64 executable 3
entry start

segment readable executable
start:
    mov rax,3c5677h ;final '7' is not displayed
    push rax
    call REG
    ;call line

    xor edi,edi     ;exit
    mov eax,60
    syscall

;---------------------------------- 
REG:push rbp        ;stack frame setup  
    mov rbp,rsp
    sub rsp,8       ;space for local char
    mov rax,[rbp+16];arg
    lea r9,[rsp-8]  ;local char
    mov rcx,16      ;divisor
    mov rsi,16      ;16 hex digits for register 
.begin:             ;get the digit
    xor rdx,rdx       ;by division
    div rcx         ;of 16   
    push rdx        ;from back to front
    dec rsi
    test rsi,rsi
    jz .disp
    jmp .begin
.disp:              ;convert and display digit
    inc rsi          
    pop rax         ;In reverse order
    add rax,30h     ;convert digit to string
    cmp rax,39h     ;if alpha
    jbe .normal
    add rax,7       ;add 7
.normal:
    mov [r9],rax    ;copy the value
    push rsi        ;save RSI for syscall 
    mov rsi,r9      ;address of char
    mov edx,1       ;size
    mov edi,1       ;stdout
    mov eax,1       ;sys_write
    syscall
    pop rsi         ;restore RSI for index
    cmp rsi,16
    je .done
    jmp .disp
.done:  
    add rsp,8       ;stack balancing
    pop rbp 
    ret

提前感谢您的帮助。

【问题讨论】:

  • 看起来很适合调试器。
  • 我也是一个 linux 菜鸟。可能需要一些时间来学习 gdb 之类的东西。

标签: linux fasm


【解决方案1】:

我相信打印最后一位数字的问题来自于您如何加载 r9。如果进入时,rsp 为 100。减去 8 (rsp = 92),然后用 rsp - 8 (r9 = 84) 加载 r9。大概您的意思是 r9 到 100,所以尝试将其更改为:

lea r9, [rsp+8]

为了更有效的解决方案,更像这样的东西怎么样(假设 rbx 中的值):

    mov r9, 16 ; How many digits to print
    mov rsi, rsp ; memory to write digits to
    sub rsp, 8 ; protect our stack

    mov edx, 1 ; size is always 1
    mov edi, 1 ; stdout is always 1

.disp:
    rol rbx, 4 ; Get the next nibble
    mov cl, bl ; copy it to scratch
    and cl, 15 ; mask out extra bits
    add cl, 0x30 ; Convert to char
    cmp cl, 0x39 ; if alpha
    jbe .normal
    add cl, 7 ; Adjust for letters

.normal:
    mov [rsi], cl ; copy the value
    mov eax, 1 ; sys_write
    syscall ;  overwrites rcx, rax, r11
    dec r9 ; Finished a digit
    jnz .disp ; Are we done?
    add rsp, 8 ; Done with the memory

【讨论】:

  • 我非常感谢大卫的替代品。这种 nibble/ROL 方法很酷 - 将 DIV 去掉 16。但我仍然需要知道我的代码有什么问题。 Linux、系统调用、ELF 和 64 位对我来说非常陌生。
  • 在您的原始代码中,打印出 16 个字节需要 32 次推送和 32 次弹出(我的是零)。这种替代方案也没有 edx 和 edi 的冗余加载,没有双 jmps,只有 1 个循环等。但是你是对的,我没有回答你原来的问题。我将编辑答案以添加它。
  • 感谢您发现错误并提供更好的替代代码。实际上,我正在尝试将 32 位 proc 转换为 64 位,看看效果如何。我没想到 64 位 asm 与所有那些 ABI、红色区域、调用约定等有如此不同。这实际上让我回到了完全菜鸟的位置。哈哈
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-21
  • 1970-01-01
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多