Skip to content

Instantly share code, notes, and snippets.

@the-nerdery-dot-info
Forked from SplittyDev/a_readme.md
Created November 10, 2016 01:33
Show Gist options
  • Save the-nerdery-dot-info/03d97a3edb87be26b506e3eff9c5d595 to your computer and use it in GitHub Desktop.
Save the-nerdery-dot-info/03d97a3edb87be26b506e3eff9c5d595 to your computer and use it in GitHub Desktop.
x86 bare metal protected mode itoa implementation

Freestanding x86 itoa implementation

For use in OS development.
Designed to be assembled with NASM, porting it over to other assemblers should be easy.

License

You are free to use, modify, distribute and sell this code.
A small message referring to this gist would be nice, though not required.

Important

This implementation uses a custom calling convention.
It is meant to be used within assembly code and does not adhere to the cdecl calling convention.

Requirements

  • Protected mode (makes use of 32-bit registers)
  • A small stack (at least 512 bits are recommended)

FAQ

Is this implementation fast?
It is reasonably fast.

Will it work in long mode?
Probably, untested though.

Why are the file names prefixed with characters?
To keep them in order.

;
; Convenience wrapper for __itoa.
; Registers are preserved.
;
; Usage:
; kitoa <value> [, base]
;
; Produces a null-terminated string in __itoabuf32.
;
%macro kitoa 1-2 10
push eax
push ebx
push ecx
mov dword eax, %1
mov dword ecx, %2
mov dword ebx, __itoabuf32
call __itoa
pop ecx
pop ecx
pop eax
%endmacro
section .rodata
;
; Conversion table for __itoa.
; Works for bases [2 ... 36].
;
__itoacvt:
db '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
section .text
;
; Routine to convert a 32-bit integer to a string.
; Registers are preserved.
;
; EAX: Source integer
; EBX: Target address
; ECX: Base
;
; Internal register layout:
; start:
; EAX: Source integer
; ECX: Target address
; EDX: Base
; checknegative:
; EAX: Source integer
; EBX: Target address (original)
; ECX: Target address (active)
; divrem:
; EAX: Source integer
; ECX: Target address (active)
; EDX: Base / Result
; reverse:
; EBX: Target address (original)
; ECX: Target address (active)
; EDX: Target address (temporary)
;
__itoa:
.start:
push eax
push ebx
push ecx
push edx
mov edx, ecx
mov ecx, ebx
.checknegative:
test eax, eax
jns .divrem
mov byte [ecx], 0x2D
inc ecx
mov ebx, ecx
neg eax
.divrem:
push edx
push ecx
mov ecx, edx
xor edx, edx
div ecx
mov byte dl, [__itoacvt + edx]
pop ecx
mov byte [ecx], dl
pop edx
inc ecx
cmp eax, 0x00
jne .divrem
mov byte [ecx], 0x00
dec ecx
.reverse:
cmp ebx, ecx
jge .end
mov byte dl, [ebx]
mov byte al, [ecx]
mov byte [ebx], al
mov byte [ecx], dl
inc ebx
dec ecx
jmp .reverse
.end:
pop edx
pop ecx
pop ebx
pop eax
ret
section .bss
;
; Buffer to store the result of __itoa in.
;
align 64
__itoabuf32:
resb 36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment