打印存储在EDX中的64位数:EAX到标准输出

时间:2014-03-24 04:33:33

标签: assembly x86 system-calls 32-bit

我在EDX中存储了大的64位数:EAX分别为21C3677C:82B40000。我试图将数字作为小数打印到控制台2432902008176640000是否有系统调用可以让我完成此操作?

3 个答案:

答案 0 :(得分:1)

有人必须怜悯这个家伙和他的同学。如果“只是打电话给printf”没有作弊,使用它也不应该作弊。我从我遇到的第一个asm程序中偷走了这个。它使用DOS中断来查找磁盘大小,并使用逗号每三位数打印dx:ax。你们可能不需要逗号。我已经修了多年 - 可能很快会做rdx:rax版本。非常适合显示阶乘。这是非常天真和低效,但仍然有效。随意改进它。当你在缓冲区中获得了字符之后,当然,这只是“Hello World”和不同的歌词。

;-----------------------------------------------
; u64toda - converts (64 bit) integer in edx:eax
; to (comma delimited) decimal representation in
; zero (was "$") terminated string in buffer pointed to by edi
;----------------------------------------
u64toda:
                pusha
                mov ebx, edx     ; stash high dword
                mov esi,0Ah      ; prepare to divide by 10
                xor ecx, ecx     ; zero the digit count
                jmp highleft     ; check is high word 0 ?
highword:
                xchg eax,ebx    ; swap high & low words
                xor edx,edx     ; zero edx for the divide!
                div esi         ; divide high word by 10
                xchg eax,ebx    ; swap 'em back
                div esi         ; divide low word including remainder
                push edx        ; remainder is our digit - save it
                inc ecx         ; count digits
highleft:
                or ebx,ebx
                jnz highword
lowleft:
                xor edx,edx          ; zero high word
                div esi              ; divide low word by 10
                push edx             ; our digit
                inc ecx              ; count it
                or eax,eax           ; 0 yet ?
                jne lowleft
                cmp ecx, byte 4      ; commas needed ?
                jl write2buf         ; nope
                xor edx,edx            ; zero high word for divide
                mov eax,ecx            ; number of digits
                mov ebx,3
                div ebx
                mov esi,edx            ; remainder = number digits before comma
                test edx,edx
                jnz write2buf        ; no remainder?
                mov esi,3             ; we can write 3 digits, then.
write2buf:
                pop eax              ; get digit back - in right order
                add al,30H           ; convert to ascii character
                stosb                ; write it to our buffer
                dec esi               ; digits before comma needed
                jnz moredigits       ; no comma needed yet
                cmp ecx,2             ; we at the end?
                jl moredigits        ; don't need comma
                mov al,','           ; write a comma
                stosb
                mov esi,03h           ; we're good for another 3 digits
moredigits:
                loop write2buf       ; write more digits - cx of 'em
                mov al,00h           ; terminate buffer with zero
                stosb
                popa
                ret
;------------------------

答案 1 :(得分:0)

哪个操作系统?在Linux上,您使用write系统调用。这是通过您正在使用的语言的标准库完成的事情。您必须自己完成从二进制到十进制ASCII字符的转换,然后将write系统调用指向该ASCII文本,给它长度,并告诉它要写入哪个文件描述符,stdout将是文件描述符1

这是查找Linux中使用的系统调用的一种方法。编写一个简单的程序并在strace下调用它,它将跟踪程序所做的所有系统调用。

例如,我编写了这个C ++程序

#include <iostream>
int main( int argc, char* argv[] )
{
    static volatile unsigned long long x = 0x21C3677C82B40000;
    std::cout << x << std::endl;
    return 0;
}

编译如下:

g++ -O3 main.cpp -o main

然后使用strace将stderr重定向到文件main.trace

运行它
$ strace -y ./main 2> main.trace
2432902008176640000
$

它写了你想要的十进制数。通过grep&#34; dev&#34;来查找设备的I / O.在追踪

$ grep dev main.trace
fstat(1</dev/pts/3>, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 3), ...}) = 0
write(1</dev/pts/3>, "2432902008176640000\n", 20) = 20
$

您会注意到C ++标准库对与fstat(1)关联的文件描述符执行了stdout,然后进行了write系统调用,并指向了数据2432902008176640000\n和长度20

答案 2 :(得分:0)

以下是如何使用printf打印64位数字的示例。此代码适用于YASM。

segment .data
    format db "Number %ld", 0x0a, 0 ; Format string for printf
    result dq 0                     ; Quad word to store the EDX:EAX result in 

segment .text
    global main
    extern printf

main:
    ; Store the 64 bit number in the quad word "result"
    mov edx, 0x21C3677C  ; Store the EDX value
    mov eax, 0x82B40000  ; Store the EAX value
    mov [result], eax    ; Lower half of "result" will be EAX
    mov [result+4], edx  ; Upper half of "result" will be EDX

    ; Print "result" with the printf function
    xor eax, eax         ; No float parameters for printf
    lea rdi, [format]    ; First parameter for printf (format string)
    mov rsi, [result]    ; Second parameter for printf ("result")
    call printf          ; Call printf

    ; End program
    xor     eax, eax     ; Return 0
    ret   

使用以下命令构建二进制文件:

yasm -f elf64 example.asm
gcc -o example example.o

更新:不使用内存的示例

segment .data
    format db "Number %ld", 0x0a, 0 ; Format string for printf

segment .text
    global main
    extern printf

main:
    ; Store the 64 bit number in register rsi
    mov edx, 0x21C3677C  ; Store the EDX value (upper half)
    mov eax, 0x82B40000  ; Store the EAX value (lower half)
    mov esi, edx         ; Place upper half in esi
    shl rsi, 32          ; Shift left 32 bits
    or  rsi, rax         ; Place the lower half in rsi

    ; Print "result" with the printf function
    xor eax, eax         ; No float parameters for printf
    lea rdi, [format]    ; First parameter for printf (format string)
    call printf          ; Call printf

    ; End program
    xor     eax, eax     ; Return 0
    ret