Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing an Int (or Int to String)

I am looking for a way to print an integer in assembler (the compiler I am using is NASM on Linux), however, after doing some research, I have not been able to find a truly viable solution. I was able to find a description for a basic algorithm to serve this purpose, and based on that I developed this code:

global _start

section .bss
digit: resb 16
count: resb 16
i: resb 16

section .data

section .text

_start:
mov             dword[i], 108eh         ; i = 4238
mov             dword[count], 1
L01:
mov             eax, dword[i]
cdq
mov             ecx, 0Ah
div             ecx  
mov             dword[digit], edx

add             dword[digit], 30h       ; add 48 to digit to make it an ASCII char
call            write_digit

inc             dword[count]

mov             eax, dword[i]
cdq
mov             ecx, 0Ah
div             ecx  
mov             dword[i], eax 
cmp             dword[i], 0Ah  
jg              L01

add             dword[i], 48            ; add 48 to i to make it an ASCII char
mov             eax, 4                  ; system call #4 = sys_write
mov             ebx, 1                  ; file descriptor 1 = stdout
mov             ecx, i                  ; store *address* of i into ecx
mov             edx, 16                 ; byte size of 16
int             80h

jmp             exit

exit:
mov             eax, 01h                ; exit()
xor             ebx, ebx                ; errno
int             80h

write_digit:
mov             eax, 4                  ; system call #4 = sys_write
mov             ebx, 1                  ; file descriptor 1 = stdout
mov             ecx, digit              ; store *address* of digit into ecx
mov             edx, 16                 ; byte size of 16
int             80h
ret

C# version of what I want to achieve (for clarity):

static string int2string(int i)
{
    Stack<char> stack = new Stack<char>();
    string s = "";

    do
    {
        stack.Push((char)((i % 10) + 48));
        i = i / 10;
    } while (i > 10);

    stack.Push((char)(i + 48));

    foreach (char c in stack)
    {
        s += c;
    }

    return s;
}

The issue is that it outputs the characters in reverse, so for 4238, the output is 8324. At first, I thought that I could use the x86 stack to solve this problem, push the digits in, and pop them out and print them at the end, however when I tried implementing that feature, it flopped and I could no longer get an output.

As a result, I am a little bit perplexed about how I can implement a stack in to this algorithm in order to accomplish my goal, aka printing an integer. I would also be interested in a simpler/better solution if one is available (as it's one of my first assembler programs).

like image 367
Wingpad Avatar asked Nov 23 '12 05:11

Wingpad


People also ask

Can you print an int in Python?

Use the print() function to print an integer value, e.g. print(my_int) . If the value is not of type integer, use the int() class to convert it to an integer and print the result, e.g. int(my_str) .

How do I print the int print?

printf("Enter an integer: "); scanf("%d", &number); Finally, the value stored in number is displayed on the screen using printf() . printf("You entered: %d", number);

How do you print a string and int on the same line?

To print a string and an integer on the same line:Use the str() class to convert the integer to a string. Use the addition (+) operator to concatenate the two strings. Use the print() function to print the result.


1 Answers

One approach is to use recursion. In this case you divide the number by 10 (getting a quotient and a remainder) and then call yourself with the quotient as the number to display; and then display the digit corresponding to the remainder.

An example of this would be:

;Input
; eax = number to display

    section .data
const10:    dd 10
    section .text

printNumber:
    push eax
    push edx
    xor edx,edx          ;edx:eax = number
    div dword [const10]  ;eax = quotient, edx = remainder
    test eax,eax         ;Is quotient zero?
    je .l1               ; yes, don't display it
    call printNumber     ;Display the quotient
.l1:
    lea eax,[edx+'0']
    call printCharacter  ;Display the remainder
    pop edx
    pop eax
    ret

Another approach is to avoid recursion by changing the divisor. An example of this would be:

;Input
; eax = number to display

    section .data
divisorTable:
    dd 1000000000
    dd 100000000
    dd 10000000
    dd 1000000
    dd 100000
    dd 10000
    dd 1000
    dd 100
    dd 10
    dd 1
    dd 0
    section .text

printNumber:
    push eax
    push ebx
    push edx
    mov ebx,divisorTable
.nextDigit:
    xor edx,edx          ;edx:eax = number
    div dword [ebx]      ;eax = quotient, edx = remainder
    add eax,'0'
    call printCharacter  ;Display the quotient
    mov eax,edx          ;eax = remainder
    add ebx,4            ;ebx = address of next divisor
    cmp dword [ebx],0    ;Have all divisors been done?
    jne .nextDigit
    pop edx
    pop ebx
    pop eax
    ret

This example doesn't suppress leading zeros, but that would be easy to add.

like image 104
Brendan Avatar answered Nov 14 '22 03:11

Brendan