打印Base-10整数x86组装Mac OS X.

时间:2015-01-19 02:45:31

标签: assembly printing x86 integer

所以我正在学习使用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 

希望这可以帮助将来的某个人。这可能不是最好的方法,但这是一种方式。

1 个答案:

答案 0 :(得分: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了解不多,所以我不能再给你提供任何暗示。