Нашел в интернетах один код печати 64битного числа:
org 100h
use16
mov edi,buff
mov eax,$FFFFFFFF
mov edx,$FFFFFFFF
; edx:eax = number to convert, edi = buffer to output (at least 20B)
; returns edi pointing after last character
push eax
push edx
push esi
push ebx
push ebp
push ecx
; test for zero in edx:eax -> special handling
mov esi,edx
or esi,eax
jz .zeroNumber
; convert other numbers by subtracting 10^k powers
mov esi,pow10table-8
.skipLeadingZero:
add esi,8
cmp edx,[esi+4]
jc .skipLeadingZero
jne .next10powerInit
cmp eax,[esi]
jc .skipLeadingZero
jmp .next10powerInit
; since here every power of 10 is counted and set into output
.next10power:
mov [edi],cl ; write counter digit of previous 10th power
inc edi
.next10powerInit:
mov ebx,[esi]
mov ebp,[esi+4] ; ebp:ebx = 10^k
test ebx,ebx
jz .finish ; only zero terminator can have lower 32b == 0
mov cl,'0'
add esi,8
.compare10power:
cmp edx,ebp
jc .next10power
jnz .sub10power
cmp eax,ebx
jc .next10power
.sub10power:
sub eax,ebx
sbb edx,ebp
inc cl
jmp .compare10power
.zeroNumber:
mov [edi],byte '0'
inc edi
.finish:
mov byte [edi],'$'
push cs
pop ds
mov dx,buff
mov ax,0924h
int 21h
pop ecx
pop ebp
pop ebx
pop esi
pop edx
pop eax
ret
pow10table:
dq 10000000000000000000
dq 1000000000000000000
dq 100000000000000000
dq 10000000000000000
dq 1000000000000000
dq 100000000000000
dq 10000000000000
dq 1000000000000
dq 100000000000
dq 10000000000
dq 1000000000
dq 100000000
dq 10000000
dq 1000000
dq 100000
dq 10000
dq 1000
dq 100
dq 10
dq 1
dq 0 ; terminator
buff:
use16
mov edi,buff
mov eax,$FFFFFFFF
mov edx,$FFFFFFFF
; edx:eax = number to convert, edi = buffer to output (at least 20B)
; returns edi pointing after last character
push eax
push edx
push esi
push ebx
push ebp
push ecx
; test for zero in edx:eax -> special handling
mov esi,edx
or esi,eax
jz .zeroNumber
; convert other numbers by subtracting 10^k powers
mov esi,pow10table-8
.skipLeadingZero:
add esi,8
cmp edx,[esi+4]
jc .skipLeadingZero
jne .next10powerInit
cmp eax,[esi]
jc .skipLeadingZero
jmp .next10powerInit
; since here every power of 10 is counted and set into output
.next10power:
mov [edi],cl ; write counter digit of previous 10th power
inc edi
.next10powerInit:
mov ebx,[esi]
mov ebp,[esi+4] ; ebp:ebx = 10^k
test ebx,ebx
jz .finish ; only zero terminator can have lower 32b == 0
mov cl,'0'
add esi,8
.compare10power:
cmp edx,ebp
jc .next10power
jnz .sub10power
cmp eax,ebx
jc .next10power
.sub10power:
sub eax,ebx
sbb edx,ebp
inc cl
jmp .compare10power
.zeroNumber:
mov [edi],byte '0'
inc edi
.finish:
mov byte [edi],'$'
push cs
pop ds
mov dx,buff
mov ax,0924h
int 21h
pop ecx
pop ebp
pop ebx
pop esi
pop edx
pop eax
ret
pow10table:
dq 10000000000000000000
dq 1000000000000000000
dq 100000000000000000
dq 10000000000000000
dq 1000000000000000
dq 100000000000000
dq 10000000000000
dq 1000000000000
dq 100000000000
dq 10000000000
dq 1000000000
dq 100000000
dq 10000000
dq 1000000
dq 100000
dq 10000
dq 1000
dq 100
dq 10
dq 1
dq 0 ; terminator
buff:
JinX предложил свой вариант:
org 100h
use16
num_size = 1024
word_count = (num_size+15)/16
; Делим
mov ebx,$FFFFFFFF
mov ebp,$7FFFFFFF;ebx ; ebp:ebx = 64-битное число 18446744073709551615
xor cx,cx ; кол-во цифр числа
mov edi,10 ; делитель
@@: xor edx,edx
xchg eax,ebp ; eax = ebp (старшая часть)
div edi ; eax = частное, edx = остаток
mov ebp,eax ; записываем старшую часть в eax
xchg eax,ebx ; eax = ebx (младшая часть)
div edi ; eax = частное, edx = остаток
mov ebx,eax ; записываем младшую часть в ebx
push dx ; цифра
inc cx
or eax,ebp ; результат не нулевой?
jnz @B
; Выводим
mov ah,2
@@: pop dx
add dl,'0'
int $21
loop @B
ret
use16
num_size = 1024
word_count = (num_size+15)/16
; Делим
mov ebx,$FFFFFFFF
mov ebp,$7FFFFFFF;ebx ; ebp:ebx = 64-битное число 18446744073709551615
xor cx,cx ; кол-во цифр числа
mov edi,10 ; делитель
@@: xor edx,edx
xchg eax,ebp ; eax = ebp (старшая часть)
div edi ; eax = частное, edx = остаток
mov ebp,eax ; записываем старшую часть в eax
xchg eax,ebx ; eax = ebx (младшая часть)
div edi ; eax = частное, edx = остаток
mov ebx,eax ; записываем младшую часть в ebx
push dx ; цифра
inc cx
or eax,ebp ; результат не нулевой?
jnz @B
; Выводим
mov ah,2
@@: pop dx
add dl,'0'
int $21
loop @B
ret
обычное деление пары edx:eax не прокатило.
Дополнение 19-02-2022 Нашел сайт, где есть немало интересных статей:
Для преобразования и форматированного вывода 32-битных значений в ассемблере используется стандартная API-функция wsprintf, но она бесполезна при работе с большими числами, например QWORD (64 бита). Значит обойдемся совсем без использования API.
;---------------------------------------------------
; Преобразование QWORD в десятичное число
; Параметры вызова:
; dwHigh - Старшее двойное слово
; dwLow - Младшее двойное слово
; lpBuff - указатель на буфер-приемник
;---------------------------------------------------
proc bignum dwHigh:DWORD, dwLow:DWORD, lpBuff:DWORD
pushad ; Сохранить все регистры
mov eax,[dwLow] ; Младшее двойное слово
mov edx,[dwHigh] ; Старшее двойное слово
mov edi,[lpBuff] ; Указатель на буфер-приемник
xchg esi,edx ; Сохранить старший dword
mov ebx,10 ; Основание системы счисления
xor ecx,ecx ; Счетчик десятичных цифр
.bignum_1:
xchg eax,esi ; Расчитать десятичную цифру
xor edx,edx
div ebx
xchg esi,eax
div ebx
or dl,'0' ; Преобразовать результат в символ цифры
push edx ; Сохранить цифру в стеке
inc ecx ; Увеличить счетчик цифр
or eax,eax ; Все преобразовали?
jnz .bignum_1
.bignum_2:
pop eax ; Записать все цифры из стека в буфер
stosb
loop .bignum_2
xor eax,eax ; Признак окончания строки
stosb
popad ; Восстановить все регистры
ret ; Ворзврат из процедуры
endp
Пример использования:
; Сегмент данных
section '.data' data readable writeable
...
buff rb 100h
; Сегмент кода
section '.code' code readable executable
...
mov edx,70655326h ; EDX:EAX = 7065532612345678h
mov eax,12345678h ; в десятичной системе это 8098970927874987640
stdcall bignum, edx, eax, buff
; После выполнения буфер содержит строку "8098970927874987640"
Функция получилась достаточно универсальной. Для преобразования числа в другую систему счисления с основанием, отличным от 10, достаточно изменить в коде функции mov ebx,10 на нужное значение. Или, как вариант, ввести дополнительный параметр вызова функции, определяющий основание.
;---------------------------------------------------
; Преобразование QWORD в десятичное число
; Параметры вызова:
; dwHigh - Старшее двойное слово
; dwLow - Младшее двойное слово
; lpBuff - указатель на буфер-приемник
;---------------------------------------------------
proc bignum dwHigh:DWORD, dwLow:DWORD, lpBuff:DWORD
pushad ; Сохранить все регистры
mov eax,[dwLow] ; Младшее двойное слово
mov edx,[dwHigh] ; Старшее двойное слово
mov edi,[lpBuff] ; Указатель на буфер-приемник
xchg esi,edx ; Сохранить старший dword
mov ebx,10 ; Основание системы счисления
xor ecx,ecx ; Счетчик десятичных цифр
.bignum_1:
xchg eax,esi ; Расчитать десятичную цифру
xor edx,edx
div ebx
xchg esi,eax
div ebx
or dl,'0' ; Преобразовать результат в символ цифры
push edx ; Сохранить цифру в стеке
inc ecx ; Увеличить счетчик цифр
or eax,eax ; Все преобразовали?
jnz .bignum_1
.bignum_2:
pop eax ; Записать все цифры из стека в буфер
stosb
loop .bignum_2
xor eax,eax ; Признак окончания строки
stosb
popad ; Восстановить все регистры
ret ; Ворзврат из процедуры
endp
Пример использования:
; Сегмент данных
section '.data' data readable writeable
...
buff rb 100h
; Сегмент кода
section '.code' code readable executable
...
mov edx,70655326h ; EDX:EAX = 7065532612345678h
mov eax,12345678h ; в десятичной системе это 8098970927874987640
stdcall bignum, edx, eax, buff
; После выполнения буфер содержит строку "8098970927874987640"
Функция получилась достаточно универсальной. Для преобразования числа в другую систему счисления с основанием, отличным от 10, достаточно изменить в коде функции mov ebx,10 на нужное значение. Или, как вариант, ввести дополнительный параметр вызова функции, определяющий основание.
Комментарии
Отправить комментарий