【问题标题】:Printing Base-10 Integers x86 Assembly Mac OS X打印 Base-10 整数 x86 程序集 Mac OS X
【发布时间】:2015-01-19 02:45:30
【问题描述】:

所以我正在学习使用 NASM 的 x86 汇编,并且我正在尝试制作一个打印出整数的简单函数。我的代码...

print_integer:          ; Integer input stored in eax
    mov ecx, 10
print_integer_loop:
    mov edx, 0
    div ecx         ; eax /= 10 | edx = eax % 10
    or edx, 0x30        ; Convert 0-9 to ‘0’-‘9’
    push edx        ; Push remaineder to stack

    mov eax, 4      ; sys_write
    mov ebx, 1      ; STDOUT
    mov ecx, esp        ; Top of Stack to ecx
    mov edx, 1      ; Print 1 byte
    int 0x80        ; syscall

    pop edx         
    cmp eax, 0      ; Compare quotient to 0
    jnz print_integer_loop

_main:
    mov eax, 4251
    call print_integer

    mov eax, 1      ; ‘Exit’ System call
    mov ebx, 0      ; Exit with error code 0
    int 0x80        ; syscall 

当我运行此代码时,没有任何反应。它只是结束而不打印任何东西。我查看了所有类似的主题,但我发现没有一个有用。我不确定出了什么问题,所以任何见解都会很棒。

编辑:我将 NASM 更新为更新的版本,因此我可以使用 x86_64 系统调用。代码如下

print_integer:              ; Assume integers is in r15
    push 0x0a               ; Push endline character
    mov r14, 1              ; Setup counter for printing 
    stack_loop:
        mov rax, r15        ; Move r15 to rax for divison
        xor rdx, rdx        ; Avoids error
        mov rcx, 10         
        div rcx             ; rax = rdx:rax / rcx  |  rdx = rdx:rax % rcx
        add rdx, '0'        ; Convert 0-9 to ‘0’-‘9’

        push rdx            ; Push remainder to stack
        mov r15, rax        ; Move quotient to r15 register     
        inc r14             ; Counter + 1   

    cmp r15, 0              ; Compare quotient to 0
    jne stack_loop          ; If not zero, loop

; Characters are now on stack in reverse order
    print_loop:
        mov rsi, rsp        ; Put remainder in rsi
        mov rdx, 1          ; Print 1 char (length)
        mov rax, 0x2000004  ; System call write
        mov rdi, 1          ; Standard output, number of bytes
        syscall             ; Invoke kernal

        dec r14             ; Counter - 1
        pop r15             ; Remove off top of stack
    cmp r14, 0
    jne print_loop
    ret 

希望这对将来的某人有所帮助。这可能不是最好的方法,但它是一种方法。

【问题讨论】:

  • 这个打印方法似乎与堆栈或其他东西混淆了,因为如果我将一个新值加载到 r15 并尝试再次打印它会打印出一些垃圾,关于它为什么会发生的任何想法?
  • 你能把你的代码发给我吗?我可以看看它,希望能够提供帮助。这是我第一次遇到这个问题。
  • 您可以在此处找到代码:pastebin.com/jcpMhTQE 似乎与堆栈 (rbp) 混淆了,哦,我正在使用 x86_64 程序集在 mac os x 上运行并使用 NASM 生成二进制文件。
  • 更新:没关系,这是我这边的错误,我刚开始使用 ASM 并使用 gcc 编译器的输出作为参考,开始时的 mov rsp,rsb 行搞砸了指向我的堆栈的指针。现在似乎运行良好。
  • 相关:How do I print an integer in Assembly Level Programming without printf from the c library? 在堆栈上创建一个字符串,因此您可以高效地执行一个 syscall。

标签: assembly printing x86 integer


【解决方案1】:

首先,您首先输出第一个余数。您用于写入十进制数的方法会以相反的顺序输出数字:数字 4251 将打印为“1524”。

那么你的程序包含一些错误:

  • 在调用操作系统时,“eax”寄存器的内容被覆盖了两次(“mov eax,4”和“int 0x80”)。您必须在“push edx”之前执行“push eax”,在“pop edx”之后执行“pop eax”以保存和恢复“eax”寄存器的内容。
  • “ecx”寄存器的内容也是如此;这可以通过使用“jnz print_integer”而不是“jnz print_integer_loop”来解决,这样“ecx”就会重新初始化。
  • 最后,在“jnz”指令之后缺少“ret”指令,因此当 print_integer 例程完成时,程序将退回到“main”例程。

现在的程序应该无休止地输出数字“1”。我在我的电脑上测试过!

固定的程序是这样的:

print_integer:
    mov ecx, 10
; print_integer_loop is no longer needed
    mov edx, 0
    div ecx
    or edx, 0x30
    push eax     ; inserted
    push edx
    mov eax, 4
    mov ebx, 1
    mov ecx, esp
    mov edx, 1
    int 0x80
    pop edx
    pop eax      ; inserted
    cmp eax, 0
    jnz print_integer  ; changed
    ret          ; inserted

main:
    mov eax, 4251
    call print_integer
    mov eax, 1
    mov ebx, 0
    int 0x80

我在 Ubuntu 12 上测试了该程序,它运行良好(但是它将数字 4251 打印为“1524”)。

顺便问一下:你为什么将你的主函数命名为“_main”?

您是否指示链接器链接到“_main”作为入口点(如果是:为什么不使用“_start”)或者您是否使用 Windows 的正常启动代码?

如果是最后一个:你程序中的“int 0x80”系统调用只能在Linux下工作;在 Windows 下运行您的代码或将代码与 Windows 代码混合并在 Linux 下运行结果将不起作用!

--- 编辑 ---

因为我没想到你会使用 Mac 我没有提到 Mac OS X:

由于 Windows 不使用“int 80h”,包含该指令的程序在 Windows 下可能会崩溃。

我知道 Mac OS X 也使用“int 80h”,所以这条指令不会导致程序崩溃。我也知道在 Mac OS X 下“int 80h”的用法与 Linux 完全不同。据我所知,参数是在 Mac OS X 下的堆栈上传递的。

你的程序的编写方式肯定只能在 Linux 下运行,而不能在 Mac OS X 下运行!

很遗憾,我对 Mac OS X 了解不多,所以我无法再给你任何提示。

【讨论】:

  • “_start”是汇编的正常命名约定吗?我对它真的很陌生,刚刚离开了我在网上找到的教程,“_main”是许多人使用的,而 main 是 C 代码的起点。另外,我显然不知道自己在做什么,因为我在基于 Intel 的 Mac 上执行此操作,那么正确的“int”调用应该是什么?
  • @CMilby:非常好的问题。 OS X 的低级调用似乎是标准的:stackoverflow.com/questions/6990885/assembly-language-in-os-x(以及其中的引用)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多