Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 3 - Assembler - Převod čísla na řetězec a naopak

V minulé lekci, Instalace kompilátoru assembleru ve Windows, jsme si nainstalovali kompilátor a vytvořili první zatím prázdný ASM projekt.

V dnešním tutoriálu si ukážeme, jak je možné převést vstup od uživatele (řetězec) na číslo, ale také způsob, kterým je možné převést číslo na řetězec.

Motivace

Stejně jako v jiných programovacích jazycích, i zde budeme vstup od uživatele dostávat jako sekvenci znaků, resp. řetězec. Vstupem, resp. vstupními daty, se rozumí např. jméno, datum narození a věk. Ve vyšším programovacím jazyku, např. v C#, je jméno datového typu String, datum narození DateTime a věk byte (člověk se více než 255 let určitě nedožije :-) ). Pokud budeme opravdu chtít pracovat s těmito datovými typy, je nutné provést konverzi. Zaměřme se nyní pouze na věk. Pro zjednodušení řekněme, že s ním chceme pracovat jako s Int32. Těm z vás, kteří už se se C# setkali, určitě došlo, že můžeme použít funkci int.Parse(...).

Návratovou hodnotou funkce int.Parse(...) je onen věk, ale je možné s ním nakládat jako s „opravdovým“ číslem.

Vraťme se nyní do světa Assembleru - světa, kde jsme odkázáni sami na sebe.

Vstupem od uživatele bude i v našem případě řetězec. Jako výstup budeme požadovat 16bitové unsigned číslo, tedy short (přesněji word). Signed čísly se budeme zabývat až při tvorbě OS, ale ti bystřejší už mají určitě tušení, jak by se to dalo udělat.

Ve druhé části tutoriálu si popíšeme opačný proces, tedy převod čísla na řetězec. Ten můžeme uplatnit například při výpisu hodnot proměnných, výsledků výpočtu, chybového kódu atd.

Funkce string_2_ushort

;
; String 2 Unsigned Short
;
; Input: DS:SI (string pointer)
; Output: AX (number)
;

string_2_ushort:
pusha
xor ax, ax
mov bx, 0x000a

.get_next_digit:
mov cl, byte [ds:si]
or cl, cl
jz .return

inc si
mul bx

sub cl, 0x30
add al, cl
jmp .get_next_digit

.return:
popa
ret

Algoritmus výše zařídí, že se sekvence znaků uložených v paměti převede na číslo typu short. Celý proces začíná inicializací potřebných registrů - AX, který bude obsahovat výsledek, a BX, v němž se nachází násobitel. Jelikož se bude hodnota v AX násobit, je nutné tento registr vynulovat.

Následovně se vstoupí do cyklu, uvnitř kterého se budou jednotlivé znaky nasouvat do čísla. Znak z řetězce se nejprve nahraje do registru CL. Následovně se podmínkou ujistíme, že nejsme na konci řetězce. Zvýšíme ukazatel, abychom se dostali na další znak, a obsah registru AX vynásobíme deseti. Tím se čísla posunout o jednu číslici doleva. Jako poslední se v cyklu provede odečtení čísla 48, čímž převedeme znak na číslici, a přičtení této číslice k hodnotě v AL. Takto dostaneme všechny znaky z řetězce do čísla.

Funkce ushort_2_string

;
; Unsigned Short 2 String
;
; Input: AX (number)
; Output: ES:DI (string pointer)
;

ushort_2_string:
push cs
pop es
mov di, .buffer
pusha
xor cx, cx
mov bx, 0x000a

.get_next_digit:
xor dx, dx
div bx
add dl, 0x30
push dx
inc cl
or ax, ax
jnz .get_next_digit

.store_next_digit:
pop ax
stosb
loop .store_next_digit
popa
ret

.buffer times 0x0006 db 0x00

I v tomto algoritmu nejdříve provedeme inicializaci registrů - ES nastavíme na CS. Spolu s DI, který bude ukazovat na proměnnou .buffer, tvoří ES:DI registrový pár ukazující na návratovou hodnotu funkce. CX se bude používat jako čítač aktuální počtu číslic. Číslo zde bude dlouhé maximálně 5 znaků, ale kvůli instrukci loop je nutné provést nulování celého registru. BX obsahuje dělitele.

Nyní vstoupíme do prvního cyklu, v němž budeme získávat a převádět jednotlivé číslice na znaky. To provedeme celočíselným dělením, resp. instrukcí div. Nejprve je nutné vynulovat DX, jelikož dělíme 16bitovým operandem. Dělení 16bitovým operandem je zvoleno kvůli velikosti výsledku, který by v případě 8bitového operandu vyvolal přetečení. Po dělením deseti dostaneme jednotlivé číslice samostatně v registru DX jako zbytek. Ke zbytku přičteme 48, čímž dostaneme znak příslušící danému číslu. Znak uložíme na zásobník a pak už je pouze nutné zkontrolovat, zdali se v AX nachází ještě nějaké číslice.

Pokud jsou veškeré číslice na zásobníku, přejdeme k jejich nahrávání do proměnné .buffer. To provedeme vybráním znaku ze zásobníku a jeho uložením na příslušnou pozici pomocí instrukce stosb. Instrukcí loop zkontrolujeme, jestli jsou zde ještě nějaké znaky na uložení do proměnné.

Po tomto cyklu už pouze obnovíme hodnoty registrů a z funkce se vrátíme. Registrový pár ES:DI bude ukazovat na návratovou hodnotu funkce, tedy převedené číslo.

Jednoduché, že? :-D

V příští lekci, Assembler - Vytvoření NASM projektu, registry a přerušení, si založíme ASM projekt a řekneme si co jsou to registry a přerušení.


 

Předchozí článek
Instalace kompilátoru assembleru ve Windows
Všechny články v sekci
Základy assembleru
Přeskočit článek
(nedoporučujeme)
Assembler - Vytvoření NASM projektu, registry a přerušení
Článek pro vás napsal Jakub Verner
Avatar
Uživatelské hodnocení:
4 hlasů
Autor se věnuje programování v x86 Assembleru.
Aktivity