Linux x86的NASM - 子程序:打印从EAX一个DWORD [英] Linux x86 NASM - Subroutine: Print a dword from EAX

查看:354
本文介绍了Linux x86的NASM - 子程序:打印从EAX一个DWORD的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我学习的Linux的x86汇编与NASM语法(哦,上帝,不是这又的,你所有的想法)。我试图做一个子程序,它只会打印EAX的值到标准输出。在code运行,并没有错误退出,但是不打印。我想不通为什么。首先,这里是我工作中的文件:

So I'm learning x86 Linux assembly with NASM syntax (Oh god, not this again, you're all thinking). I'm trying to make a subroutine that will simply print the value in EAX to stdout. The code runs and exits without error, but nothing prints. I can't figure out why. First of all, here is the file I'm working in:

segment .bss
    to_print:   resd 1

segment .text
    global print_eax_val

print_eax_val:                  ;       (top)
    push    dword ebx           ;Stack:  edx
    push    dword ecx           ;        ecx
    push    dword edx           ;        ebx
                                ;       (bot)

    mov     ecx,eax             ;ecx = eax

    mov     [to_print],ecx      ;to_print = ecx

    mov     eax, 4              ;sys_write
    mov     ebx, 1              ;to stdout
    add     ecx, 47             ;add 47 for ASCII numbers
    mov     edx, 2              ;double word = 2 bytes
    int     0x80

    mov     eax, [to_print]     ;eax = original val
    pop     edx                 ;pop the registers back from the stack
    pop     ecx
    pop     ebx                 ;Stack: empty

    ret

这是从我的主文件,它看起来像这样(这可能是无关紧要的,除非我失去了一些激烈的)呼吁。

This is called from my main file, which looks like this (this is probably irrelevant, unless I'm missing something drastic).

segment .data
        hello   db      "Hello world!", 0
        newline db      0xA
        len     equ $ - hello
        len2    equ $ - newline

segment .text
        extern print_nl
        extern print_eax_val
        global main

main:
        enter   0,0

        call    print_nl

        mov     eax, 1

        call    print_eax_val

        mov     ebx, 0          ;exit code = 0 (normal)
        mov     eax, 1          ;exit command
        int     0x80            ;ask kernel to quit

print_nl 只是另一个子程序定义并打印一个换行符。这种成功运行并打印预期一个新行。

print_nl is just another subroutine that defines and prints a newline. This runs successfully and prints a new line as expected.

问题是否与我的 SYS_WRITE 调用长度参数呢?我给它2,这是一个 DWORD ,这是双方的 EAX 寄存器的大小尺寸我的 to_print 标签,我与保留RESD 1 。我试图改变长度1,4,8,16,32和绝望的......毫无效果。

Does the problem have to do with the length parameter for my sys_write call? I'm giving it 2, which is the size of a dword, which is the size of both the EAX register and my to_print label, which I reserved with resd 1. I tried changing the length to 1, 4, 8, 16, and 32 out of desperation... Nothing worked.

编辑:的人谁不知道,这里是我如何固定code:(我将把星号上线,我改变):

For anyone who is wondering, here is how I fixed the code: (I will put asterisks on lines that I changed):

segment .bss
    to_print:   resd 1

segment .text
        global print_eax_val

print_eax_val:                      ;       (top)
        push    dword ebx           ;Stack:  edx
        push    dword ecx           ;        ecx
        push    dword edx           ;        ebx
                                    ;       (bot)

        mov     ecx,eax             ;ecx = eax

        mov     [to_print],ecx        ;to_print = ecx

****    add     dword [to_print], 48

        mov     eax, 4              ;sys_write
        mov     ebx, 1              ;to stdout
****    mov     ecx, to_print
        mov     edx, 2
        int     0x80

****    sub     dword [to_print], 48
        mov     eax, [to_print]     ;eax = original val
        pop     edx                 ;pop the registers back from the stack
        pop     ecx
        pop     ebx                 ;Stack: empty

        ret

基本上, ECX 必须包含的地址的要打印的块,而不是本身的价值。由于所选的答案是指出,这会的只有的工作,如果EAX的范围为0-9。

Basically, ecx must contain the address of the block you want to print, NOT the value itself. As is pointed out in the selected answer, this will only work if eax is in the range 0-9.

编辑2 :那么我是一个有点困惑了SYS_WRITE第二个参数(一个保存在 EDX )。我认为它只是指的是字节数。因此,对于一个 DWORD ,为我所用,这将是适当使用4那里,因为一个双字为4个字节,即32位。我猜测它的工作,因为86是小端。所以在内存中, to_print 的十六进制值应该是这样的:

EDIT 2: So I was a little bit confused about the 2nd parameter for sys_write (the one stored in edx). I think it just refers to a number of bytes. So for a dword, as I was using, it would be proper to use 4 there, because a double word is 4 bytes, or 32 bits. I'm guessing it worked because x86 is little-endian. So in memory, the hex value of to_print would look like this:

90 00 00 00

和与两个供应长度,SYS_WRITE得到:

And with a supplied length of two, sys_write gets:

90 00

所以价值幸运的是不会被破坏。

So the value luckily doesn't get corrupted.

我后来改变了code存储 to_print 为一个字节,而不是使用 RESB 1 和访问它使用字节而不是 DWORD ...字节是在这里很好,因为我知道我不打算给 to_print 9以上的值。

I later changed the code to store to_print as a byte instead, using resb 1 and accessing it using byte instead of dword... A byte is fine here, because I know I'm not going to give to_print a value above 9.

推荐答案

我在汇编很生疏,但它看起来像ECX包含值48,当它应该包含要写入缓冲区的地址。

I'm very rusty at assembler, but it looks like ECX contains the value 48, when it should contain the address of the buffer to be written.

我presume你打算什么 print_eax_val 是采取EAX的二进制值,添加ASCII偏移位 0 (这应该是48,而不是47),然后打印单个字符。要做到这一点,在 to_print 存储的价值,把 to_print 的地址在ECX前加48,并设置长度(EDX)为1,因为你写的只有一个字符。

I presume what you intended in print_eax_val is to take the binary value of EAX, add the ASCII offset to digit 0 (which should have been 48, not 47) and then print that single character. To do this, add 48 before storing the value in to_print, put the address of to_print in ECX, and set the length (EDX) to 1, because you're writing only one character.

现在请记住,这会为EAX值工作为0x0000,只有0x0009之间。当你走过去的9你会得到其他的ASCII字符。

Now remember that this will work for EAX values between 0x0000 and 0x0009 only. When you go past 9 you will get other ASCII characters.

解释如何采取EAX的任意的二进制值,并将其转换为可以打印一个小数字符串远远超出SO范围

Explaining how to take an arbitrary binary value of EAX and convert it to a decimal string that can be printed is far beyond the scope of SO.

这篇关于Linux x86的NASM - 子程序:打印从EAX一个DWORD的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆