How to print a number in assembly NASM?












13















Suppose that I have an integer number in a register, how can I print it? Can you show a simple example code?



I already know how to print a string such as "hello, world".



I'm developing on Linux.










share|improve this question

























  • Please specify the OS where the program will run.

    – Alexey Frunze
    Nov 19 '11 at 12:56






  • 1





    Related: convert an integer to an ASCII decimal string in a buffer on the stack and print it with Linux write system call, not using printf or any other functions. With comments and explanation.

    – Peter Cordes
    Nov 18 '17 at 18:14


















13















Suppose that I have an integer number in a register, how can I print it? Can you show a simple example code?



I already know how to print a string such as "hello, world".



I'm developing on Linux.










share|improve this question

























  • Please specify the OS where the program will run.

    – Alexey Frunze
    Nov 19 '11 at 12:56






  • 1





    Related: convert an integer to an ASCII decimal string in a buffer on the stack and print it with Linux write system call, not using printf or any other functions. With comments and explanation.

    – Peter Cordes
    Nov 18 '17 at 18:14
















13












13








13


7






Suppose that I have an integer number in a register, how can I print it? Can you show a simple example code?



I already know how to print a string such as "hello, world".



I'm developing on Linux.










share|improve this question
















Suppose that I have an integer number in a register, how can I print it? Can you show a simple example code?



I already know how to print a string such as "hello, world".



I'm developing on Linux.







assembly nasm






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 24 '14 at 2:42









alex

341k170768914




341k170768914










asked Nov 19 '11 at 12:46









AR89AR89

1,16652037




1,16652037













  • Please specify the OS where the program will run.

    – Alexey Frunze
    Nov 19 '11 at 12:56






  • 1





    Related: convert an integer to an ASCII decimal string in a buffer on the stack and print it with Linux write system call, not using printf or any other functions. With comments and explanation.

    – Peter Cordes
    Nov 18 '17 at 18:14





















  • Please specify the OS where the program will run.

    – Alexey Frunze
    Nov 19 '11 at 12:56






  • 1





    Related: convert an integer to an ASCII decimal string in a buffer on the stack and print it with Linux write system call, not using printf or any other functions. With comments and explanation.

    – Peter Cordes
    Nov 18 '17 at 18:14



















Please specify the OS where the program will run.

– Alexey Frunze
Nov 19 '11 at 12:56





Please specify the OS where the program will run.

– Alexey Frunze
Nov 19 '11 at 12:56




1




1





Related: convert an integer to an ASCII decimal string in a buffer on the stack and print it with Linux write system call, not using printf or any other functions. With comments and explanation.

– Peter Cordes
Nov 18 '17 at 18:14







Related: convert an integer to an ASCII decimal string in a buffer on the stack and print it with Linux write system call, not using printf or any other functions. With comments and explanation.

– Peter Cordes
Nov 18 '17 at 18:14














6 Answers
6






active

oldest

votes


















11














If you're already on Linux, there's no need to do the conversion yourself. Just use printf instead:



;
; assemble and link with:
; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
;
section .text
global main
extern printf

main:

mov eax, 0xDEADBEEF
push eax
push message
call printf
add esp, 8
ret

message db "Register = %08X", 10, 0


Note that printf uses the cdecl calling convention so we need to restore the stack pointer afterwards, i.e. add 4 bytes per parameter passed to the function.






share|improve this answer
























  • Thanks, it seems to be the what I was looking for. Do you know if it works also on Mac os X?

    – AR89
    Nov 19 '11 at 15:17











  • How to compile it on 64-bit?

    – Figen Güngör
    Dec 19 '12 at 9:43











  • @FigenGüngör stackoverflow.com/a/32853546/895245

    – Ciro Santilli 新疆改造中心 六四事件 法轮功
    Sep 29 '15 at 20:52



















12














You have to convert it in a string; if you're talking about hex numbers it's pretty easy. Any number can be represented this way:



0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3


So when you have this number you have to split it like I've shown then convert every "section" to its ASCII equivalent.

Getting the four parts is easily done with some bit magic, in particular with a right shift to move the part we're interested in in the first four bits then AND the result with 0xf to isolate it from the rest. Here's what I mean (soppose we want to take the 3):



0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003


Now that we have a single number we have to convert it into its ASCII value. If the number is smaller or equal than 9 we can just add 0's ASCII value (0x30), if it's greater than 9 we have to use a's ASCII value (0x61).

Here it is, now we just have to code it:



    mov si, ???         ; si points to the target buffer
mov ax, 0a31fh ; ax contains the number we want to convert
mov bx, ax ; store a copy in bx
xor dx, dx ; dx will contain the result
mov cx, 3 ; cx's our counter

convert_loop:
mov ax, bx ; load the number into ax
and ax, 0fh ; we want the first 4 bits
cmp ax, 9h ; check what we should add
ja greater_than_9
add ax, 30h ; 0x30 ('0')
jmp converted

greater_than_9:
add ax, 61h ; or 0x61 ('a')

converted:
xchg al, ah ; put a null terminator after it
mov [si], ax ; (will be overwritten unless this
inc si ; is the last one)

shr bx, 4 ; get the next part
dec cx ; one less to do
jnz convert_loop

sub di, 4 ; di still points to the target buffer


PS: I know this is 16 bit code but I still use the old TASM :P



PPS: this is Intel syntax, converting to AT&T syntax isn't difficult though, look here.






share|improve this answer


























  • @downvoter: reason?

    – BlackBear
    Nov 19 '11 at 14:12











  • You don't need AT&T syntax to run this on linux.

    – Andrei Bârsan
    Feb 5 '13 at 18:52











  • @AndreiBârsan: You're right, fixed that.. It's such an old answer :)

    – BlackBear
    Feb 5 '13 at 21:13






  • 1





    IMHO, this answer is better since you don't need the C runtime (which a call to printf(...) requires.

    – Andrei Bârsan
    Feb 6 '13 at 12:41






  • 1





    @AndreiBârsan yes, and it's kind of pointless using the C runtime in assembly

    – BlackBear
    Feb 6 '13 at 18:25



















4














Linux x86-64 with printf



extern printf, exit
section .data
format db "%x", 10, 0
section .text
global main
main:
sub rsp, 8
mov rsi, 0x12345678
mov rdi, format
xor rax, rax
call printf
mov rdi, 0
call exit


Then:



nasm -f elf64 main.asm
gcc main.o
./a.out


The "hard points" of the System V AMD64 ABI calling convention:





  • sub rsp, 8: How to write assembly language hello world program for 64 bit Mac OS X using printf?


  • mov rax, 1: Why is %eax zeroed before a call to printf?


If you want hex without the C library: https://stackoverflow.com/a/32756303/895245






share|improve this answer

































    1














    It depends on the architecture/environment you are using.



    For instance, if I want to display a number on linux, the ASM code will be different from the one I would use on windows.



    Edit:



    You can refer to THIS for an example of conversion.






    share|improve this answer


























    • A Linux example would be fine.

      – AR89
      Nov 19 '11 at 13:04











    • @AR89 it's a bad job.. You have to convert the number to ASCII first. Take a look at the edited question.

      – AlQafir
      Nov 19 '11 at 13:19



















    0














    I'm relatively new to assembly, and this obviously is not the best solution,
    but it's working. The main function is _iprint, it first checks whether the
    number in eax is negative, and prints a minus sign if so, than it proceeds
    by printing the individual numbers by calling the function _dprint for
    every digit. The idea is the following, if we have 512 than it is equal to: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, so we can found the last digit of a number by dividing it by 10, and
    getting the reminder R, but if we do it in a loop than digits will be in a
    reverse order, so we use the stack for pushing them, and after that when
    writing them to stdout they are popped out in right order.



    ; Build        : nasm -f elf -o baz.o baz.asm
    ; ld -m elf_i386 -o baz baz.o
    section .bss
    c: resb 1 ; character buffer
    section .data
    section .text
    ; writes an ascii character from eax to stdout
    _cprint:
    pushad ; push registers
    mov [c], eax ; store ascii value at c
    mov eax, 0x04 ; sys_write
    mov ebx, 1 ; stdout
    mov ecx, c ; copy c to ecx
    mov edx, 1 ; one character
    int 0x80 ; syscall
    popad ; pop registers
    ret ; bye
    ; writes a digit stored in eax to stdout
    _dprint:
    pushad ; push registers
    add eax, '0' ; get digit's ascii code
    mov [c], eax ; store it at c
    mov eax, 0x04 ; sys_write
    mov ebx, 1 ; stdout
    mov ecx, c ; pass the address of c to ecx
    mov edx, 1 ; one character
    int 0x80 ; syscall
    popad ; pop registers
    ret ; bye
    ; now lets try to write a function which will write an integer
    ; number stored in eax in decimal at stdout
    _iprint:
    pushad ; push registers
    cmp eax, 0 ; check if eax is negative
    jge Pos ; if not proceed in the usual manner
    push eax ; store eax
    mov eax, '-' ; print minus sign
    call _cprint ; call character printing function
    pop eax ; restore eax
    neg eax ; make eax positive
    Pos:
    mov ebx, 10 ; base
    mov ecx, 1 ; number of digits counter
    Cycle1:
    mov edx, 0 ; set edx to zero before dividing otherwise the
    ; program gives an error: SIGFPE arithmetic exception
    div ebx ; divide eax with ebx now eax holds the
    ; quotent and edx the reminder
    push edx ; digits we have to write are in reverse order
    cmp eax, 0 ; exit loop condition
    jz EndLoop1 ; we are done
    inc ecx ; increment number of digits counter
    jmp Cycle1 ; loop back
    EndLoop1:
    ; write the integer digits by poping them out from the stack
    Cycle2:
    pop eax ; pop up the digits we have stored
    call _dprint ; and print them to stdout
    dec ecx ; decrement number of digits counter
    jz EndLoop2 ; if it's zero we are done
    jmp Cycle2 ; loop back
    EndLoop2:
    popad ; pop registers
    ret ; bye
    global _start
    _start:
    nop ; gdb break point
    mov eax, -345 ;
    call _iprint ;
    mov eax, 0x01 ; sys_exit
    mov ebx, 0 ; error code
    int 0x80 ; край





    share|improve this answer
























    • You can add '0' and store your digits in a buffer as you produce them. Use dec do move the pointer downwards. When you're done, you have a pointer to the last digit you stored, so you can pass that to sys_write() (along with the digit count). This is much more efficient than making a separate system call for every byte, and doesn't really take more code. It's easy to allocate a buffer long enough to hold the longest possible string of digits, and start at the end, because you know how many decimal digits 2^32 has.

      – Peter Cordes
      Jul 29 '17 at 7:59











    • related: I wrote an integer->string loop as part of this extended-precision Fibonacci code-golf answer. See the .toascii_digit: loop. Of course, that's optimized for size, so it uses a slow div instead of a multiply trick.

      – Peter Cordes
      Jul 29 '17 at 8:01








    • 1





      Thank you this is definitely preferable than calling sys_write for every digit:)

      – baz
      Aug 15 '17 at 15:44











    • I posted my int->string + sys_write code as a stand-alone function on another question, with comments.

      – Peter Cordes
      Nov 18 '17 at 18:17



















    0














    Because you didn't say about number representation I wrote the following code for unsigned number with any base(of course not too big), so you could use it:



    BITS 32
    global _start

    section .text
    _start:

    mov eax, 762002099 ; unsigned number to print
    mov ebx, 36 ; base to represent the number, do not set it too big
    call print

    ;exit
    mov eax, 1
    xor ebx, ebx
    int 0x80

    print:
    mov ecx, esp
    sub esp, 36 ; reserve space for the number string, for base-2 it takes 33 bytes with new line, aligned by 4 bytes it takes 36 bytes.

    mov edi, 1
    dec ecx
    mov [ecx], byte 10

    print_loop:

    xor edx, edx
    div ebx
    cmp dl, 9 ; if reminder>9 go to use_letter
    jg use_letter

    add dl, '0'
    jmp after_use_letter

    use_letter:
    add dl, 'W' ; letters from 'a' to ... in ascii code

    after_use_letter:
    dec ecx
    inc edi
    mov [ecx],dl
    test eax, eax
    jnz print_loop

    ; system call to print, ecx is a pointer on the string
    mov eax, 4 ; system call number (sys_write)
    mov ebx, 1 ; file descriptor (stdout)
    mov edx, edi ; length of the string
    int 0x80

    add esp, 36 ; release space for the number string

    ret


    It's not optimised for numbers with base of power of two and doesn't use printf from libc.



    The function print outputs the number with a new line. The number string is formed on stack. Compile by nasm.



    Output:



    clockz


    https://github.com/tigertv/stackoverflow-answers/tree/master/8194141-how-to-print-a-number-in-assembly-nasm






    share|improve this answer


























    • You're using space below ESP. That's only safe in cases like this where you know there are no signal handlers installed, and shouldn't be used in functions that could be called in other contexts. 32-bit Linux doesn't guarantee a red-zone. Also, use xor edx,edx / div or cdq / idiv so the zero or sign-extension of the dividend matches the signedness of the division. In this case you want xor/div so you always have a positive remainder. If you want to treat your input as signed, you'll want to test/js and print the unsigned absolute value (with a leading - if needed).

      – Peter Cordes
      Dec 30 '18 at 7:18











    • @PeterCordes, Hi, Peter! You're right about safety. It's a partial solution and I didn't think about signed numbers.

      – TigerTV.ru
      Dec 30 '18 at 17:09











    • You should still change idiv to div so it works for the full range of unsigned numbers. Hmm, actually this might be safe anyway, because 2^32-1 / 10 doesn't overflow EAX. zero-extending into edx:eax gives you a signed non-negative dividend from 0..2^32-1.

      – Peter Cordes
      Dec 30 '18 at 20:57













    • @PeterCordes, The idiv has been replaced. Also I added base for the number. What do you think about it? And else I reserved a buffer on stack for number string with size 32.

      – TigerTV.ru
      Dec 31 '18 at 1:13











    • add esp, 32 should be sub to reserve space. You're stepping on the caller's stack space. mov byte [ecx], 10 would be more efficient than setting a register first. Or even push 10 / mov ecx, esp / sub esp, 32. (For your current version, a large number with base=2 will use 32 digits, but you use up one of your 32 with a newline.)

      – Peter Cordes
      Dec 31 '18 at 1:25











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8194141%2fhow-to-print-a-number-in-assembly-nasm%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    6 Answers
    6






    active

    oldest

    votes








    6 Answers
    6






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    11














    If you're already on Linux, there's no need to do the conversion yourself. Just use printf instead:



    ;
    ; assemble and link with:
    ; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
    ;
    section .text
    global main
    extern printf

    main:

    mov eax, 0xDEADBEEF
    push eax
    push message
    call printf
    add esp, 8
    ret

    message db "Register = %08X", 10, 0


    Note that printf uses the cdecl calling convention so we need to restore the stack pointer afterwards, i.e. add 4 bytes per parameter passed to the function.






    share|improve this answer
























    • Thanks, it seems to be the what I was looking for. Do you know if it works also on Mac os X?

      – AR89
      Nov 19 '11 at 15:17











    • How to compile it on 64-bit?

      – Figen Güngör
      Dec 19 '12 at 9:43











    • @FigenGüngör stackoverflow.com/a/32853546/895245

      – Ciro Santilli 新疆改造中心 六四事件 法轮功
      Sep 29 '15 at 20:52
















    11














    If you're already on Linux, there's no need to do the conversion yourself. Just use printf instead:



    ;
    ; assemble and link with:
    ; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
    ;
    section .text
    global main
    extern printf

    main:

    mov eax, 0xDEADBEEF
    push eax
    push message
    call printf
    add esp, 8
    ret

    message db "Register = %08X", 10, 0


    Note that printf uses the cdecl calling convention so we need to restore the stack pointer afterwards, i.e. add 4 bytes per parameter passed to the function.






    share|improve this answer
























    • Thanks, it seems to be the what I was looking for. Do you know if it works also on Mac os X?

      – AR89
      Nov 19 '11 at 15:17











    • How to compile it on 64-bit?

      – Figen Güngör
      Dec 19 '12 at 9:43











    • @FigenGüngör stackoverflow.com/a/32853546/895245

      – Ciro Santilli 新疆改造中心 六四事件 法轮功
      Sep 29 '15 at 20:52














    11












    11








    11







    If you're already on Linux, there's no need to do the conversion yourself. Just use printf instead:



    ;
    ; assemble and link with:
    ; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
    ;
    section .text
    global main
    extern printf

    main:

    mov eax, 0xDEADBEEF
    push eax
    push message
    call printf
    add esp, 8
    ret

    message db "Register = %08X", 10, 0


    Note that printf uses the cdecl calling convention so we need to restore the stack pointer afterwards, i.e. add 4 bytes per parameter passed to the function.






    share|improve this answer













    If you're already on Linux, there's no need to do the conversion yourself. Just use printf instead:



    ;
    ; assemble and link with:
    ; nasm -f elf printf-test.asm && gcc -m32 -o printf-test printf-test.o
    ;
    section .text
    global main
    extern printf

    main:

    mov eax, 0xDEADBEEF
    push eax
    push message
    call printf
    add esp, 8
    ret

    message db "Register = %08X", 10, 0


    Note that printf uses the cdecl calling convention so we need to restore the stack pointer afterwards, i.e. add 4 bytes per parameter passed to the function.







    share|improve this answer












    share|improve this answer



    share|improve this answer










    answered Nov 19 '11 at 13:36









    MartinMartin

    27k136373




    27k136373













    • Thanks, it seems to be the what I was looking for. Do you know if it works also on Mac os X?

      – AR89
      Nov 19 '11 at 15:17











    • How to compile it on 64-bit?

      – Figen Güngör
      Dec 19 '12 at 9:43











    • @FigenGüngör stackoverflow.com/a/32853546/895245

      – Ciro Santilli 新疆改造中心 六四事件 法轮功
      Sep 29 '15 at 20:52



















    • Thanks, it seems to be the what I was looking for. Do you know if it works also on Mac os X?

      – AR89
      Nov 19 '11 at 15:17











    • How to compile it on 64-bit?

      – Figen Güngör
      Dec 19 '12 at 9:43











    • @FigenGüngör stackoverflow.com/a/32853546/895245

      – Ciro Santilli 新疆改造中心 六四事件 法轮功
      Sep 29 '15 at 20:52

















    Thanks, it seems to be the what I was looking for. Do you know if it works also on Mac os X?

    – AR89
    Nov 19 '11 at 15:17





    Thanks, it seems to be the what I was looking for. Do you know if it works also on Mac os X?

    – AR89
    Nov 19 '11 at 15:17













    How to compile it on 64-bit?

    – Figen Güngör
    Dec 19 '12 at 9:43





    How to compile it on 64-bit?

    – Figen Güngör
    Dec 19 '12 at 9:43













    @FigenGüngör stackoverflow.com/a/32853546/895245

    – Ciro Santilli 新疆改造中心 六四事件 法轮功
    Sep 29 '15 at 20:52





    @FigenGüngör stackoverflow.com/a/32853546/895245

    – Ciro Santilli 新疆改造中心 六四事件 法轮功
    Sep 29 '15 at 20:52













    12














    You have to convert it in a string; if you're talking about hex numbers it's pretty easy. Any number can be represented this way:



    0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3


    So when you have this number you have to split it like I've shown then convert every "section" to its ASCII equivalent.

    Getting the four parts is easily done with some bit magic, in particular with a right shift to move the part we're interested in in the first four bits then AND the result with 0xf to isolate it from the rest. Here's what I mean (soppose we want to take the 3):



    0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003


    Now that we have a single number we have to convert it into its ASCII value. If the number is smaller or equal than 9 we can just add 0's ASCII value (0x30), if it's greater than 9 we have to use a's ASCII value (0x61).

    Here it is, now we just have to code it:



        mov si, ???         ; si points to the target buffer
    mov ax, 0a31fh ; ax contains the number we want to convert
    mov bx, ax ; store a copy in bx
    xor dx, dx ; dx will contain the result
    mov cx, 3 ; cx's our counter

    convert_loop:
    mov ax, bx ; load the number into ax
    and ax, 0fh ; we want the first 4 bits
    cmp ax, 9h ; check what we should add
    ja greater_than_9
    add ax, 30h ; 0x30 ('0')
    jmp converted

    greater_than_9:
    add ax, 61h ; or 0x61 ('a')

    converted:
    xchg al, ah ; put a null terminator after it
    mov [si], ax ; (will be overwritten unless this
    inc si ; is the last one)

    shr bx, 4 ; get the next part
    dec cx ; one less to do
    jnz convert_loop

    sub di, 4 ; di still points to the target buffer


    PS: I know this is 16 bit code but I still use the old TASM :P



    PPS: this is Intel syntax, converting to AT&T syntax isn't difficult though, look here.






    share|improve this answer


























    • @downvoter: reason?

      – BlackBear
      Nov 19 '11 at 14:12











    • You don't need AT&T syntax to run this on linux.

      – Andrei Bârsan
      Feb 5 '13 at 18:52











    • @AndreiBârsan: You're right, fixed that.. It's such an old answer :)

      – BlackBear
      Feb 5 '13 at 21:13






    • 1





      IMHO, this answer is better since you don't need the C runtime (which a call to printf(...) requires.

      – Andrei Bârsan
      Feb 6 '13 at 12:41






    • 1





      @AndreiBârsan yes, and it's kind of pointless using the C runtime in assembly

      – BlackBear
      Feb 6 '13 at 18:25
















    12














    You have to convert it in a string; if you're talking about hex numbers it's pretty easy. Any number can be represented this way:



    0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3


    So when you have this number you have to split it like I've shown then convert every "section" to its ASCII equivalent.

    Getting the four parts is easily done with some bit magic, in particular with a right shift to move the part we're interested in in the first four bits then AND the result with 0xf to isolate it from the rest. Here's what I mean (soppose we want to take the 3):



    0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003


    Now that we have a single number we have to convert it into its ASCII value. If the number is smaller or equal than 9 we can just add 0's ASCII value (0x30), if it's greater than 9 we have to use a's ASCII value (0x61).

    Here it is, now we just have to code it:



        mov si, ???         ; si points to the target buffer
    mov ax, 0a31fh ; ax contains the number we want to convert
    mov bx, ax ; store a copy in bx
    xor dx, dx ; dx will contain the result
    mov cx, 3 ; cx's our counter

    convert_loop:
    mov ax, bx ; load the number into ax
    and ax, 0fh ; we want the first 4 bits
    cmp ax, 9h ; check what we should add
    ja greater_than_9
    add ax, 30h ; 0x30 ('0')
    jmp converted

    greater_than_9:
    add ax, 61h ; or 0x61 ('a')

    converted:
    xchg al, ah ; put a null terminator after it
    mov [si], ax ; (will be overwritten unless this
    inc si ; is the last one)

    shr bx, 4 ; get the next part
    dec cx ; one less to do
    jnz convert_loop

    sub di, 4 ; di still points to the target buffer


    PS: I know this is 16 bit code but I still use the old TASM :P



    PPS: this is Intel syntax, converting to AT&T syntax isn't difficult though, look here.






    share|improve this answer


























    • @downvoter: reason?

      – BlackBear
      Nov 19 '11 at 14:12











    • You don't need AT&T syntax to run this on linux.

      – Andrei Bârsan
      Feb 5 '13 at 18:52











    • @AndreiBârsan: You're right, fixed that.. It's such an old answer :)

      – BlackBear
      Feb 5 '13 at 21:13






    • 1





      IMHO, this answer is better since you don't need the C runtime (which a call to printf(...) requires.

      – Andrei Bârsan
      Feb 6 '13 at 12:41






    • 1





      @AndreiBârsan yes, and it's kind of pointless using the C runtime in assembly

      – BlackBear
      Feb 6 '13 at 18:25














    12












    12








    12







    You have to convert it in a string; if you're talking about hex numbers it's pretty easy. Any number can be represented this way:



    0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3


    So when you have this number you have to split it like I've shown then convert every "section" to its ASCII equivalent.

    Getting the four parts is easily done with some bit magic, in particular with a right shift to move the part we're interested in in the first four bits then AND the result with 0xf to isolate it from the rest. Here's what I mean (soppose we want to take the 3):



    0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003


    Now that we have a single number we have to convert it into its ASCII value. If the number is smaller or equal than 9 we can just add 0's ASCII value (0x30), if it's greater than 9 we have to use a's ASCII value (0x61).

    Here it is, now we just have to code it:



        mov si, ???         ; si points to the target buffer
    mov ax, 0a31fh ; ax contains the number we want to convert
    mov bx, ax ; store a copy in bx
    xor dx, dx ; dx will contain the result
    mov cx, 3 ; cx's our counter

    convert_loop:
    mov ax, bx ; load the number into ax
    and ax, 0fh ; we want the first 4 bits
    cmp ax, 9h ; check what we should add
    ja greater_than_9
    add ax, 30h ; 0x30 ('0')
    jmp converted

    greater_than_9:
    add ax, 61h ; or 0x61 ('a')

    converted:
    xchg al, ah ; put a null terminator after it
    mov [si], ax ; (will be overwritten unless this
    inc si ; is the last one)

    shr bx, 4 ; get the next part
    dec cx ; one less to do
    jnz convert_loop

    sub di, 4 ; di still points to the target buffer


    PS: I know this is 16 bit code but I still use the old TASM :P



    PPS: this is Intel syntax, converting to AT&T syntax isn't difficult though, look here.






    share|improve this answer















    You have to convert it in a string; if you're talking about hex numbers it's pretty easy. Any number can be represented this way:



    0xa31f = 0xf * 16^0 + 0x1 * 16^1 + 3 * 16^2 + 0xa * 16^3


    So when you have this number you have to split it like I've shown then convert every "section" to its ASCII equivalent.

    Getting the four parts is easily done with some bit magic, in particular with a right shift to move the part we're interested in in the first four bits then AND the result with 0xf to isolate it from the rest. Here's what I mean (soppose we want to take the 3):



    0xa31f -> shift right by 8 = 0x00a3 -> AND with 0xf = 0x0003


    Now that we have a single number we have to convert it into its ASCII value. If the number is smaller or equal than 9 we can just add 0's ASCII value (0x30), if it's greater than 9 we have to use a's ASCII value (0x61).

    Here it is, now we just have to code it:



        mov si, ???         ; si points to the target buffer
    mov ax, 0a31fh ; ax contains the number we want to convert
    mov bx, ax ; store a copy in bx
    xor dx, dx ; dx will contain the result
    mov cx, 3 ; cx's our counter

    convert_loop:
    mov ax, bx ; load the number into ax
    and ax, 0fh ; we want the first 4 bits
    cmp ax, 9h ; check what we should add
    ja greater_than_9
    add ax, 30h ; 0x30 ('0')
    jmp converted

    greater_than_9:
    add ax, 61h ; or 0x61 ('a')

    converted:
    xchg al, ah ; put a null terminator after it
    mov [si], ax ; (will be overwritten unless this
    inc si ; is the last one)

    shr bx, 4 ; get the next part
    dec cx ; one less to do
    jnz convert_loop

    sub di, 4 ; di still points to the target buffer


    PS: I know this is 16 bit code but I still use the old TASM :P



    PPS: this is Intel syntax, converting to AT&T syntax isn't difficult though, look here.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 5 '13 at 21:12

























    answered Nov 19 '11 at 13:31









    BlackBearBlackBear

    15.3k83367




    15.3k83367













    • @downvoter: reason?

      – BlackBear
      Nov 19 '11 at 14:12











    • You don't need AT&T syntax to run this on linux.

      – Andrei Bârsan
      Feb 5 '13 at 18:52











    • @AndreiBârsan: You're right, fixed that.. It's such an old answer :)

      – BlackBear
      Feb 5 '13 at 21:13






    • 1





      IMHO, this answer is better since you don't need the C runtime (which a call to printf(...) requires.

      – Andrei Bârsan
      Feb 6 '13 at 12:41






    • 1





      @AndreiBârsan yes, and it's kind of pointless using the C runtime in assembly

      – BlackBear
      Feb 6 '13 at 18:25



















    • @downvoter: reason?

      – BlackBear
      Nov 19 '11 at 14:12











    • You don't need AT&T syntax to run this on linux.

      – Andrei Bârsan
      Feb 5 '13 at 18:52











    • @AndreiBârsan: You're right, fixed that.. It's such an old answer :)

      – BlackBear
      Feb 5 '13 at 21:13






    • 1





      IMHO, this answer is better since you don't need the C runtime (which a call to printf(...) requires.

      – Andrei Bârsan
      Feb 6 '13 at 12:41






    • 1





      @AndreiBârsan yes, and it's kind of pointless using the C runtime in assembly

      – BlackBear
      Feb 6 '13 at 18:25

















    @downvoter: reason?

    – BlackBear
    Nov 19 '11 at 14:12





    @downvoter: reason?

    – BlackBear
    Nov 19 '11 at 14:12













    You don't need AT&T syntax to run this on linux.

    – Andrei Bârsan
    Feb 5 '13 at 18:52





    You don't need AT&T syntax to run this on linux.

    – Andrei Bârsan
    Feb 5 '13 at 18:52













    @AndreiBârsan: You're right, fixed that.. It's such an old answer :)

    – BlackBear
    Feb 5 '13 at 21:13





    @AndreiBârsan: You're right, fixed that.. It's such an old answer :)

    – BlackBear
    Feb 5 '13 at 21:13




    1




    1





    IMHO, this answer is better since you don't need the C runtime (which a call to printf(...) requires.

    – Andrei Bârsan
    Feb 6 '13 at 12:41





    IMHO, this answer is better since you don't need the C runtime (which a call to printf(...) requires.

    – Andrei Bârsan
    Feb 6 '13 at 12:41




    1




    1





    @AndreiBârsan yes, and it's kind of pointless using the C runtime in assembly

    – BlackBear
    Feb 6 '13 at 18:25





    @AndreiBârsan yes, and it's kind of pointless using the C runtime in assembly

    – BlackBear
    Feb 6 '13 at 18:25











    4














    Linux x86-64 with printf



    extern printf, exit
    section .data
    format db "%x", 10, 0
    section .text
    global main
    main:
    sub rsp, 8
    mov rsi, 0x12345678
    mov rdi, format
    xor rax, rax
    call printf
    mov rdi, 0
    call exit


    Then:



    nasm -f elf64 main.asm
    gcc main.o
    ./a.out


    The "hard points" of the System V AMD64 ABI calling convention:





    • sub rsp, 8: How to write assembly language hello world program for 64 bit Mac OS X using printf?


    • mov rax, 1: Why is %eax zeroed before a call to printf?


    If you want hex without the C library: https://stackoverflow.com/a/32756303/895245






    share|improve this answer






























      4














      Linux x86-64 with printf



      extern printf, exit
      section .data
      format db "%x", 10, 0
      section .text
      global main
      main:
      sub rsp, 8
      mov rsi, 0x12345678
      mov rdi, format
      xor rax, rax
      call printf
      mov rdi, 0
      call exit


      Then:



      nasm -f elf64 main.asm
      gcc main.o
      ./a.out


      The "hard points" of the System V AMD64 ABI calling convention:





      • sub rsp, 8: How to write assembly language hello world program for 64 bit Mac OS X using printf?


      • mov rax, 1: Why is %eax zeroed before a call to printf?


      If you want hex without the C library: https://stackoverflow.com/a/32756303/895245






      share|improve this answer




























        4












        4








        4







        Linux x86-64 with printf



        extern printf, exit
        section .data
        format db "%x", 10, 0
        section .text
        global main
        main:
        sub rsp, 8
        mov rsi, 0x12345678
        mov rdi, format
        xor rax, rax
        call printf
        mov rdi, 0
        call exit


        Then:



        nasm -f elf64 main.asm
        gcc main.o
        ./a.out


        The "hard points" of the System V AMD64 ABI calling convention:





        • sub rsp, 8: How to write assembly language hello world program for 64 bit Mac OS X using printf?


        • mov rax, 1: Why is %eax zeroed before a call to printf?


        If you want hex without the C library: https://stackoverflow.com/a/32756303/895245






        share|improve this answer















        Linux x86-64 with printf



        extern printf, exit
        section .data
        format db "%x", 10, 0
        section .text
        global main
        main:
        sub rsp, 8
        mov rsi, 0x12345678
        mov rdi, format
        xor rax, rax
        call printf
        mov rdi, 0
        call exit


        Then:



        nasm -f elf64 main.asm
        gcc main.o
        ./a.out


        The "hard points" of the System V AMD64 ABI calling convention:





        • sub rsp, 8: How to write assembly language hello world program for 64 bit Mac OS X using printf?


        • mov rax, 1: Why is %eax zeroed before a call to printf?


        If you want hex without the C library: https://stackoverflow.com/a/32756303/895245







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited May 23 '17 at 11:47









        Community

        11




        11










        answered Sep 29 '15 at 20:52









        Ciro Santilli 新疆改造中心 六四事件 法轮功Ciro Santilli 新疆改造中心 六四事件 法轮功

        141k33542458




        141k33542458























            1














            It depends on the architecture/environment you are using.



            For instance, if I want to display a number on linux, the ASM code will be different from the one I would use on windows.



            Edit:



            You can refer to THIS for an example of conversion.






            share|improve this answer


























            • A Linux example would be fine.

              – AR89
              Nov 19 '11 at 13:04











            • @AR89 it's a bad job.. You have to convert the number to ASCII first. Take a look at the edited question.

              – AlQafir
              Nov 19 '11 at 13:19
















            1














            It depends on the architecture/environment you are using.



            For instance, if I want to display a number on linux, the ASM code will be different from the one I would use on windows.



            Edit:



            You can refer to THIS for an example of conversion.






            share|improve this answer


























            • A Linux example would be fine.

              – AR89
              Nov 19 '11 at 13:04











            • @AR89 it's a bad job.. You have to convert the number to ASCII first. Take a look at the edited question.

              – AlQafir
              Nov 19 '11 at 13:19














            1












            1








            1







            It depends on the architecture/environment you are using.



            For instance, if I want to display a number on linux, the ASM code will be different from the one I would use on windows.



            Edit:



            You can refer to THIS for an example of conversion.






            share|improve this answer















            It depends on the architecture/environment you are using.



            For instance, if I want to display a number on linux, the ASM code will be different from the one I would use on windows.



            Edit:



            You can refer to THIS for an example of conversion.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 19 '11 at 13:18

























            answered Nov 19 '11 at 12:49









            AlQafirAlQafir

            2,2531322




            2,2531322













            • A Linux example would be fine.

              – AR89
              Nov 19 '11 at 13:04











            • @AR89 it's a bad job.. You have to convert the number to ASCII first. Take a look at the edited question.

              – AlQafir
              Nov 19 '11 at 13:19



















            • A Linux example would be fine.

              – AR89
              Nov 19 '11 at 13:04











            • @AR89 it's a bad job.. You have to convert the number to ASCII first. Take a look at the edited question.

              – AlQafir
              Nov 19 '11 at 13:19

















            A Linux example would be fine.

            – AR89
            Nov 19 '11 at 13:04





            A Linux example would be fine.

            – AR89
            Nov 19 '11 at 13:04













            @AR89 it's a bad job.. You have to convert the number to ASCII first. Take a look at the edited question.

            – AlQafir
            Nov 19 '11 at 13:19





            @AR89 it's a bad job.. You have to convert the number to ASCII first. Take a look at the edited question.

            – AlQafir
            Nov 19 '11 at 13:19











            0














            I'm relatively new to assembly, and this obviously is not the best solution,
            but it's working. The main function is _iprint, it first checks whether the
            number in eax is negative, and prints a minus sign if so, than it proceeds
            by printing the individual numbers by calling the function _dprint for
            every digit. The idea is the following, if we have 512 than it is equal to: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, so we can found the last digit of a number by dividing it by 10, and
            getting the reminder R, but if we do it in a loop than digits will be in a
            reverse order, so we use the stack for pushing them, and after that when
            writing them to stdout they are popped out in right order.



            ; Build        : nasm -f elf -o baz.o baz.asm
            ; ld -m elf_i386 -o baz baz.o
            section .bss
            c: resb 1 ; character buffer
            section .data
            section .text
            ; writes an ascii character from eax to stdout
            _cprint:
            pushad ; push registers
            mov [c], eax ; store ascii value at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; copy c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; writes a digit stored in eax to stdout
            _dprint:
            pushad ; push registers
            add eax, '0' ; get digit's ascii code
            mov [c], eax ; store it at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; pass the address of c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; now lets try to write a function which will write an integer
            ; number stored in eax in decimal at stdout
            _iprint:
            pushad ; push registers
            cmp eax, 0 ; check if eax is negative
            jge Pos ; if not proceed in the usual manner
            push eax ; store eax
            mov eax, '-' ; print minus sign
            call _cprint ; call character printing function
            pop eax ; restore eax
            neg eax ; make eax positive
            Pos:
            mov ebx, 10 ; base
            mov ecx, 1 ; number of digits counter
            Cycle1:
            mov edx, 0 ; set edx to zero before dividing otherwise the
            ; program gives an error: SIGFPE arithmetic exception
            div ebx ; divide eax with ebx now eax holds the
            ; quotent and edx the reminder
            push edx ; digits we have to write are in reverse order
            cmp eax, 0 ; exit loop condition
            jz EndLoop1 ; we are done
            inc ecx ; increment number of digits counter
            jmp Cycle1 ; loop back
            EndLoop1:
            ; write the integer digits by poping them out from the stack
            Cycle2:
            pop eax ; pop up the digits we have stored
            call _dprint ; and print them to stdout
            dec ecx ; decrement number of digits counter
            jz EndLoop2 ; if it's zero we are done
            jmp Cycle2 ; loop back
            EndLoop2:
            popad ; pop registers
            ret ; bye
            global _start
            _start:
            nop ; gdb break point
            mov eax, -345 ;
            call _iprint ;
            mov eax, 0x01 ; sys_exit
            mov ebx, 0 ; error code
            int 0x80 ; край





            share|improve this answer
























            • You can add '0' and store your digits in a buffer as you produce them. Use dec do move the pointer downwards. When you're done, you have a pointer to the last digit you stored, so you can pass that to sys_write() (along with the digit count). This is much more efficient than making a separate system call for every byte, and doesn't really take more code. It's easy to allocate a buffer long enough to hold the longest possible string of digits, and start at the end, because you know how many decimal digits 2^32 has.

              – Peter Cordes
              Jul 29 '17 at 7:59











            • related: I wrote an integer->string loop as part of this extended-precision Fibonacci code-golf answer. See the .toascii_digit: loop. Of course, that's optimized for size, so it uses a slow div instead of a multiply trick.

              – Peter Cordes
              Jul 29 '17 at 8:01








            • 1





              Thank you this is definitely preferable than calling sys_write for every digit:)

              – baz
              Aug 15 '17 at 15:44











            • I posted my int->string + sys_write code as a stand-alone function on another question, with comments.

              – Peter Cordes
              Nov 18 '17 at 18:17
















            0














            I'm relatively new to assembly, and this obviously is not the best solution,
            but it's working. The main function is _iprint, it first checks whether the
            number in eax is negative, and prints a minus sign if so, than it proceeds
            by printing the individual numbers by calling the function _dprint for
            every digit. The idea is the following, if we have 512 than it is equal to: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, so we can found the last digit of a number by dividing it by 10, and
            getting the reminder R, but if we do it in a loop than digits will be in a
            reverse order, so we use the stack for pushing them, and after that when
            writing them to stdout they are popped out in right order.



            ; Build        : nasm -f elf -o baz.o baz.asm
            ; ld -m elf_i386 -o baz baz.o
            section .bss
            c: resb 1 ; character buffer
            section .data
            section .text
            ; writes an ascii character from eax to stdout
            _cprint:
            pushad ; push registers
            mov [c], eax ; store ascii value at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; copy c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; writes a digit stored in eax to stdout
            _dprint:
            pushad ; push registers
            add eax, '0' ; get digit's ascii code
            mov [c], eax ; store it at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; pass the address of c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; now lets try to write a function which will write an integer
            ; number stored in eax in decimal at stdout
            _iprint:
            pushad ; push registers
            cmp eax, 0 ; check if eax is negative
            jge Pos ; if not proceed in the usual manner
            push eax ; store eax
            mov eax, '-' ; print minus sign
            call _cprint ; call character printing function
            pop eax ; restore eax
            neg eax ; make eax positive
            Pos:
            mov ebx, 10 ; base
            mov ecx, 1 ; number of digits counter
            Cycle1:
            mov edx, 0 ; set edx to zero before dividing otherwise the
            ; program gives an error: SIGFPE arithmetic exception
            div ebx ; divide eax with ebx now eax holds the
            ; quotent and edx the reminder
            push edx ; digits we have to write are in reverse order
            cmp eax, 0 ; exit loop condition
            jz EndLoop1 ; we are done
            inc ecx ; increment number of digits counter
            jmp Cycle1 ; loop back
            EndLoop1:
            ; write the integer digits by poping them out from the stack
            Cycle2:
            pop eax ; pop up the digits we have stored
            call _dprint ; and print them to stdout
            dec ecx ; decrement number of digits counter
            jz EndLoop2 ; if it's zero we are done
            jmp Cycle2 ; loop back
            EndLoop2:
            popad ; pop registers
            ret ; bye
            global _start
            _start:
            nop ; gdb break point
            mov eax, -345 ;
            call _iprint ;
            mov eax, 0x01 ; sys_exit
            mov ebx, 0 ; error code
            int 0x80 ; край





            share|improve this answer
























            • You can add '0' and store your digits in a buffer as you produce them. Use dec do move the pointer downwards. When you're done, you have a pointer to the last digit you stored, so you can pass that to sys_write() (along with the digit count). This is much more efficient than making a separate system call for every byte, and doesn't really take more code. It's easy to allocate a buffer long enough to hold the longest possible string of digits, and start at the end, because you know how many decimal digits 2^32 has.

              – Peter Cordes
              Jul 29 '17 at 7:59











            • related: I wrote an integer->string loop as part of this extended-precision Fibonacci code-golf answer. See the .toascii_digit: loop. Of course, that's optimized for size, so it uses a slow div instead of a multiply trick.

              – Peter Cordes
              Jul 29 '17 at 8:01








            • 1





              Thank you this is definitely preferable than calling sys_write for every digit:)

              – baz
              Aug 15 '17 at 15:44











            • I posted my int->string + sys_write code as a stand-alone function on another question, with comments.

              – Peter Cordes
              Nov 18 '17 at 18:17














            0












            0








            0







            I'm relatively new to assembly, and this obviously is not the best solution,
            but it's working. The main function is _iprint, it first checks whether the
            number in eax is negative, and prints a minus sign if so, than it proceeds
            by printing the individual numbers by calling the function _dprint for
            every digit. The idea is the following, if we have 512 than it is equal to: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, so we can found the last digit of a number by dividing it by 10, and
            getting the reminder R, but if we do it in a loop than digits will be in a
            reverse order, so we use the stack for pushing them, and after that when
            writing them to stdout they are popped out in right order.



            ; Build        : nasm -f elf -o baz.o baz.asm
            ; ld -m elf_i386 -o baz baz.o
            section .bss
            c: resb 1 ; character buffer
            section .data
            section .text
            ; writes an ascii character from eax to stdout
            _cprint:
            pushad ; push registers
            mov [c], eax ; store ascii value at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; copy c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; writes a digit stored in eax to stdout
            _dprint:
            pushad ; push registers
            add eax, '0' ; get digit's ascii code
            mov [c], eax ; store it at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; pass the address of c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; now lets try to write a function which will write an integer
            ; number stored in eax in decimal at stdout
            _iprint:
            pushad ; push registers
            cmp eax, 0 ; check if eax is negative
            jge Pos ; if not proceed in the usual manner
            push eax ; store eax
            mov eax, '-' ; print minus sign
            call _cprint ; call character printing function
            pop eax ; restore eax
            neg eax ; make eax positive
            Pos:
            mov ebx, 10 ; base
            mov ecx, 1 ; number of digits counter
            Cycle1:
            mov edx, 0 ; set edx to zero before dividing otherwise the
            ; program gives an error: SIGFPE arithmetic exception
            div ebx ; divide eax with ebx now eax holds the
            ; quotent and edx the reminder
            push edx ; digits we have to write are in reverse order
            cmp eax, 0 ; exit loop condition
            jz EndLoop1 ; we are done
            inc ecx ; increment number of digits counter
            jmp Cycle1 ; loop back
            EndLoop1:
            ; write the integer digits by poping them out from the stack
            Cycle2:
            pop eax ; pop up the digits we have stored
            call _dprint ; and print them to stdout
            dec ecx ; decrement number of digits counter
            jz EndLoop2 ; if it's zero we are done
            jmp Cycle2 ; loop back
            EndLoop2:
            popad ; pop registers
            ret ; bye
            global _start
            _start:
            nop ; gdb break point
            mov eax, -345 ;
            call _iprint ;
            mov eax, 0x01 ; sys_exit
            mov ebx, 0 ; error code
            int 0x80 ; край





            share|improve this answer













            I'm relatively new to assembly, and this obviously is not the best solution,
            but it's working. The main function is _iprint, it first checks whether the
            number in eax is negative, and prints a minus sign if so, than it proceeds
            by printing the individual numbers by calling the function _dprint for
            every digit. The idea is the following, if we have 512 than it is equal to: 512 = (5 * 10 + 1) * 10 + 2 = Q * 10 + R, so we can found the last digit of a number by dividing it by 10, and
            getting the reminder R, but if we do it in a loop than digits will be in a
            reverse order, so we use the stack for pushing them, and after that when
            writing them to stdout they are popped out in right order.



            ; Build        : nasm -f elf -o baz.o baz.asm
            ; ld -m elf_i386 -o baz baz.o
            section .bss
            c: resb 1 ; character buffer
            section .data
            section .text
            ; writes an ascii character from eax to stdout
            _cprint:
            pushad ; push registers
            mov [c], eax ; store ascii value at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; copy c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; writes a digit stored in eax to stdout
            _dprint:
            pushad ; push registers
            add eax, '0' ; get digit's ascii code
            mov [c], eax ; store it at c
            mov eax, 0x04 ; sys_write
            mov ebx, 1 ; stdout
            mov ecx, c ; pass the address of c to ecx
            mov edx, 1 ; one character
            int 0x80 ; syscall
            popad ; pop registers
            ret ; bye
            ; now lets try to write a function which will write an integer
            ; number stored in eax in decimal at stdout
            _iprint:
            pushad ; push registers
            cmp eax, 0 ; check if eax is negative
            jge Pos ; if not proceed in the usual manner
            push eax ; store eax
            mov eax, '-' ; print minus sign
            call _cprint ; call character printing function
            pop eax ; restore eax
            neg eax ; make eax positive
            Pos:
            mov ebx, 10 ; base
            mov ecx, 1 ; number of digits counter
            Cycle1:
            mov edx, 0 ; set edx to zero before dividing otherwise the
            ; program gives an error: SIGFPE arithmetic exception
            div ebx ; divide eax with ebx now eax holds the
            ; quotent and edx the reminder
            push edx ; digits we have to write are in reverse order
            cmp eax, 0 ; exit loop condition
            jz EndLoop1 ; we are done
            inc ecx ; increment number of digits counter
            jmp Cycle1 ; loop back
            EndLoop1:
            ; write the integer digits by poping them out from the stack
            Cycle2:
            pop eax ; pop up the digits we have stored
            call _dprint ; and print them to stdout
            dec ecx ; decrement number of digits counter
            jz EndLoop2 ; if it's zero we are done
            jmp Cycle2 ; loop back
            EndLoop2:
            popad ; pop registers
            ret ; bye
            global _start
            _start:
            nop ; gdb break point
            mov eax, -345 ;
            call _iprint ;
            mov eax, 0x01 ; sys_exit
            mov ebx, 0 ; error code
            int 0x80 ; край






            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered May 23 '17 at 6:57









            bazbaz

            33735




            33735













            • You can add '0' and store your digits in a buffer as you produce them. Use dec do move the pointer downwards. When you're done, you have a pointer to the last digit you stored, so you can pass that to sys_write() (along with the digit count). This is much more efficient than making a separate system call for every byte, and doesn't really take more code. It's easy to allocate a buffer long enough to hold the longest possible string of digits, and start at the end, because you know how many decimal digits 2^32 has.

              – Peter Cordes
              Jul 29 '17 at 7:59











            • related: I wrote an integer->string loop as part of this extended-precision Fibonacci code-golf answer. See the .toascii_digit: loop. Of course, that's optimized for size, so it uses a slow div instead of a multiply trick.

              – Peter Cordes
              Jul 29 '17 at 8:01








            • 1





              Thank you this is definitely preferable than calling sys_write for every digit:)

              – baz
              Aug 15 '17 at 15:44











            • I posted my int->string + sys_write code as a stand-alone function on another question, with comments.

              – Peter Cordes
              Nov 18 '17 at 18:17



















            • You can add '0' and store your digits in a buffer as you produce them. Use dec do move the pointer downwards. When you're done, you have a pointer to the last digit you stored, so you can pass that to sys_write() (along with the digit count). This is much more efficient than making a separate system call for every byte, and doesn't really take more code. It's easy to allocate a buffer long enough to hold the longest possible string of digits, and start at the end, because you know how many decimal digits 2^32 has.

              – Peter Cordes
              Jul 29 '17 at 7:59











            • related: I wrote an integer->string loop as part of this extended-precision Fibonacci code-golf answer. See the .toascii_digit: loop. Of course, that's optimized for size, so it uses a slow div instead of a multiply trick.

              – Peter Cordes
              Jul 29 '17 at 8:01








            • 1





              Thank you this is definitely preferable than calling sys_write for every digit:)

              – baz
              Aug 15 '17 at 15:44











            • I posted my int->string + sys_write code as a stand-alone function on another question, with comments.

              – Peter Cordes
              Nov 18 '17 at 18:17

















            You can add '0' and store your digits in a buffer as you produce them. Use dec do move the pointer downwards. When you're done, you have a pointer to the last digit you stored, so you can pass that to sys_write() (along with the digit count). This is much more efficient than making a separate system call for every byte, and doesn't really take more code. It's easy to allocate a buffer long enough to hold the longest possible string of digits, and start at the end, because you know how many decimal digits 2^32 has.

            – Peter Cordes
            Jul 29 '17 at 7:59





            You can add '0' and store your digits in a buffer as you produce them. Use dec do move the pointer downwards. When you're done, you have a pointer to the last digit you stored, so you can pass that to sys_write() (along with the digit count). This is much more efficient than making a separate system call for every byte, and doesn't really take more code. It's easy to allocate a buffer long enough to hold the longest possible string of digits, and start at the end, because you know how many decimal digits 2^32 has.

            – Peter Cordes
            Jul 29 '17 at 7:59













            related: I wrote an integer->string loop as part of this extended-precision Fibonacci code-golf answer. See the .toascii_digit: loop. Of course, that's optimized for size, so it uses a slow div instead of a multiply trick.

            – Peter Cordes
            Jul 29 '17 at 8:01







            related: I wrote an integer->string loop as part of this extended-precision Fibonacci code-golf answer. See the .toascii_digit: loop. Of course, that's optimized for size, so it uses a slow div instead of a multiply trick.

            – Peter Cordes
            Jul 29 '17 at 8:01






            1




            1





            Thank you this is definitely preferable than calling sys_write for every digit:)

            – baz
            Aug 15 '17 at 15:44





            Thank you this is definitely preferable than calling sys_write for every digit:)

            – baz
            Aug 15 '17 at 15:44













            I posted my int->string + sys_write code as a stand-alone function on another question, with comments.

            – Peter Cordes
            Nov 18 '17 at 18:17





            I posted my int->string + sys_write code as a stand-alone function on another question, with comments.

            – Peter Cordes
            Nov 18 '17 at 18:17











            0














            Because you didn't say about number representation I wrote the following code for unsigned number with any base(of course not too big), so you could use it:



            BITS 32
            global _start

            section .text
            _start:

            mov eax, 762002099 ; unsigned number to print
            mov ebx, 36 ; base to represent the number, do not set it too big
            call print

            ;exit
            mov eax, 1
            xor ebx, ebx
            int 0x80

            print:
            mov ecx, esp
            sub esp, 36 ; reserve space for the number string, for base-2 it takes 33 bytes with new line, aligned by 4 bytes it takes 36 bytes.

            mov edi, 1
            dec ecx
            mov [ecx], byte 10

            print_loop:

            xor edx, edx
            div ebx
            cmp dl, 9 ; if reminder>9 go to use_letter
            jg use_letter

            add dl, '0'
            jmp after_use_letter

            use_letter:
            add dl, 'W' ; letters from 'a' to ... in ascii code

            after_use_letter:
            dec ecx
            inc edi
            mov [ecx],dl
            test eax, eax
            jnz print_loop

            ; system call to print, ecx is a pointer on the string
            mov eax, 4 ; system call number (sys_write)
            mov ebx, 1 ; file descriptor (stdout)
            mov edx, edi ; length of the string
            int 0x80

            add esp, 36 ; release space for the number string

            ret


            It's not optimised for numbers with base of power of two and doesn't use printf from libc.



            The function print outputs the number with a new line. The number string is formed on stack. Compile by nasm.



            Output:



            clockz


            https://github.com/tigertv/stackoverflow-answers/tree/master/8194141-how-to-print-a-number-in-assembly-nasm






            share|improve this answer


























            • You're using space below ESP. That's only safe in cases like this where you know there are no signal handlers installed, and shouldn't be used in functions that could be called in other contexts. 32-bit Linux doesn't guarantee a red-zone. Also, use xor edx,edx / div or cdq / idiv so the zero or sign-extension of the dividend matches the signedness of the division. In this case you want xor/div so you always have a positive remainder. If you want to treat your input as signed, you'll want to test/js and print the unsigned absolute value (with a leading - if needed).

              – Peter Cordes
              Dec 30 '18 at 7:18











            • @PeterCordes, Hi, Peter! You're right about safety. It's a partial solution and I didn't think about signed numbers.

              – TigerTV.ru
              Dec 30 '18 at 17:09











            • You should still change idiv to div so it works for the full range of unsigned numbers. Hmm, actually this might be safe anyway, because 2^32-1 / 10 doesn't overflow EAX. zero-extending into edx:eax gives you a signed non-negative dividend from 0..2^32-1.

              – Peter Cordes
              Dec 30 '18 at 20:57













            • @PeterCordes, The idiv has been replaced. Also I added base for the number. What do you think about it? And else I reserved a buffer on stack for number string with size 32.

              – TigerTV.ru
              Dec 31 '18 at 1:13











            • add esp, 32 should be sub to reserve space. You're stepping on the caller's stack space. mov byte [ecx], 10 would be more efficient than setting a register first. Or even push 10 / mov ecx, esp / sub esp, 32. (For your current version, a large number with base=2 will use 32 digits, but you use up one of your 32 with a newline.)

              – Peter Cordes
              Dec 31 '18 at 1:25
















            0














            Because you didn't say about number representation I wrote the following code for unsigned number with any base(of course not too big), so you could use it:



            BITS 32
            global _start

            section .text
            _start:

            mov eax, 762002099 ; unsigned number to print
            mov ebx, 36 ; base to represent the number, do not set it too big
            call print

            ;exit
            mov eax, 1
            xor ebx, ebx
            int 0x80

            print:
            mov ecx, esp
            sub esp, 36 ; reserve space for the number string, for base-2 it takes 33 bytes with new line, aligned by 4 bytes it takes 36 bytes.

            mov edi, 1
            dec ecx
            mov [ecx], byte 10

            print_loop:

            xor edx, edx
            div ebx
            cmp dl, 9 ; if reminder>9 go to use_letter
            jg use_letter

            add dl, '0'
            jmp after_use_letter

            use_letter:
            add dl, 'W' ; letters from 'a' to ... in ascii code

            after_use_letter:
            dec ecx
            inc edi
            mov [ecx],dl
            test eax, eax
            jnz print_loop

            ; system call to print, ecx is a pointer on the string
            mov eax, 4 ; system call number (sys_write)
            mov ebx, 1 ; file descriptor (stdout)
            mov edx, edi ; length of the string
            int 0x80

            add esp, 36 ; release space for the number string

            ret


            It's not optimised for numbers with base of power of two and doesn't use printf from libc.



            The function print outputs the number with a new line. The number string is formed on stack. Compile by nasm.



            Output:



            clockz


            https://github.com/tigertv/stackoverflow-answers/tree/master/8194141-how-to-print-a-number-in-assembly-nasm






            share|improve this answer


























            • You're using space below ESP. That's only safe in cases like this where you know there are no signal handlers installed, and shouldn't be used in functions that could be called in other contexts. 32-bit Linux doesn't guarantee a red-zone. Also, use xor edx,edx / div or cdq / idiv so the zero or sign-extension of the dividend matches the signedness of the division. In this case you want xor/div so you always have a positive remainder. If you want to treat your input as signed, you'll want to test/js and print the unsigned absolute value (with a leading - if needed).

              – Peter Cordes
              Dec 30 '18 at 7:18











            • @PeterCordes, Hi, Peter! You're right about safety. It's a partial solution and I didn't think about signed numbers.

              – TigerTV.ru
              Dec 30 '18 at 17:09











            • You should still change idiv to div so it works for the full range of unsigned numbers. Hmm, actually this might be safe anyway, because 2^32-1 / 10 doesn't overflow EAX. zero-extending into edx:eax gives you a signed non-negative dividend from 0..2^32-1.

              – Peter Cordes
              Dec 30 '18 at 20:57













            • @PeterCordes, The idiv has been replaced. Also I added base for the number. What do you think about it? And else I reserved a buffer on stack for number string with size 32.

              – TigerTV.ru
              Dec 31 '18 at 1:13











            • add esp, 32 should be sub to reserve space. You're stepping on the caller's stack space. mov byte [ecx], 10 would be more efficient than setting a register first. Or even push 10 / mov ecx, esp / sub esp, 32. (For your current version, a large number with base=2 will use 32 digits, but you use up one of your 32 with a newline.)

              – Peter Cordes
              Dec 31 '18 at 1:25














            0












            0








            0







            Because you didn't say about number representation I wrote the following code for unsigned number with any base(of course not too big), so you could use it:



            BITS 32
            global _start

            section .text
            _start:

            mov eax, 762002099 ; unsigned number to print
            mov ebx, 36 ; base to represent the number, do not set it too big
            call print

            ;exit
            mov eax, 1
            xor ebx, ebx
            int 0x80

            print:
            mov ecx, esp
            sub esp, 36 ; reserve space for the number string, for base-2 it takes 33 bytes with new line, aligned by 4 bytes it takes 36 bytes.

            mov edi, 1
            dec ecx
            mov [ecx], byte 10

            print_loop:

            xor edx, edx
            div ebx
            cmp dl, 9 ; if reminder>9 go to use_letter
            jg use_letter

            add dl, '0'
            jmp after_use_letter

            use_letter:
            add dl, 'W' ; letters from 'a' to ... in ascii code

            after_use_letter:
            dec ecx
            inc edi
            mov [ecx],dl
            test eax, eax
            jnz print_loop

            ; system call to print, ecx is a pointer on the string
            mov eax, 4 ; system call number (sys_write)
            mov ebx, 1 ; file descriptor (stdout)
            mov edx, edi ; length of the string
            int 0x80

            add esp, 36 ; release space for the number string

            ret


            It's not optimised for numbers with base of power of two and doesn't use printf from libc.



            The function print outputs the number with a new line. The number string is formed on stack. Compile by nasm.



            Output:



            clockz


            https://github.com/tigertv/stackoverflow-answers/tree/master/8194141-how-to-print-a-number-in-assembly-nasm






            share|improve this answer















            Because you didn't say about number representation I wrote the following code for unsigned number with any base(of course not too big), so you could use it:



            BITS 32
            global _start

            section .text
            _start:

            mov eax, 762002099 ; unsigned number to print
            mov ebx, 36 ; base to represent the number, do not set it too big
            call print

            ;exit
            mov eax, 1
            xor ebx, ebx
            int 0x80

            print:
            mov ecx, esp
            sub esp, 36 ; reserve space for the number string, for base-2 it takes 33 bytes with new line, aligned by 4 bytes it takes 36 bytes.

            mov edi, 1
            dec ecx
            mov [ecx], byte 10

            print_loop:

            xor edx, edx
            div ebx
            cmp dl, 9 ; if reminder>9 go to use_letter
            jg use_letter

            add dl, '0'
            jmp after_use_letter

            use_letter:
            add dl, 'W' ; letters from 'a' to ... in ascii code

            after_use_letter:
            dec ecx
            inc edi
            mov [ecx],dl
            test eax, eax
            jnz print_loop

            ; system call to print, ecx is a pointer on the string
            mov eax, 4 ; system call number (sys_write)
            mov ebx, 1 ; file descriptor (stdout)
            mov edx, edi ; length of the string
            int 0x80

            add esp, 36 ; release space for the number string

            ret


            It's not optimised for numbers with base of power of two and doesn't use printf from libc.



            The function print outputs the number with a new line. The number string is formed on stack. Compile by nasm.



            Output:



            clockz


            https://github.com/tigertv/stackoverflow-answers/tree/master/8194141-how-to-print-a-number-in-assembly-nasm







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 31 '18 at 13:52

























            answered Dec 29 '18 at 2:09









            TigerTV.ruTigerTV.ru

            7801621




            7801621













            • You're using space below ESP. That's only safe in cases like this where you know there are no signal handlers installed, and shouldn't be used in functions that could be called in other contexts. 32-bit Linux doesn't guarantee a red-zone. Also, use xor edx,edx / div or cdq / idiv so the zero or sign-extension of the dividend matches the signedness of the division. In this case you want xor/div so you always have a positive remainder. If you want to treat your input as signed, you'll want to test/js and print the unsigned absolute value (with a leading - if needed).

              – Peter Cordes
              Dec 30 '18 at 7:18











            • @PeterCordes, Hi, Peter! You're right about safety. It's a partial solution and I didn't think about signed numbers.

              – TigerTV.ru
              Dec 30 '18 at 17:09











            • You should still change idiv to div so it works for the full range of unsigned numbers. Hmm, actually this might be safe anyway, because 2^32-1 / 10 doesn't overflow EAX. zero-extending into edx:eax gives you a signed non-negative dividend from 0..2^32-1.

              – Peter Cordes
              Dec 30 '18 at 20:57













            • @PeterCordes, The idiv has been replaced. Also I added base for the number. What do you think about it? And else I reserved a buffer on stack for number string with size 32.

              – TigerTV.ru
              Dec 31 '18 at 1:13











            • add esp, 32 should be sub to reserve space. You're stepping on the caller's stack space. mov byte [ecx], 10 would be more efficient than setting a register first. Or even push 10 / mov ecx, esp / sub esp, 32. (For your current version, a large number with base=2 will use 32 digits, but you use up one of your 32 with a newline.)

              – Peter Cordes
              Dec 31 '18 at 1:25



















            • You're using space below ESP. That's only safe in cases like this where you know there are no signal handlers installed, and shouldn't be used in functions that could be called in other contexts. 32-bit Linux doesn't guarantee a red-zone. Also, use xor edx,edx / div or cdq / idiv so the zero or sign-extension of the dividend matches the signedness of the division. In this case you want xor/div so you always have a positive remainder. If you want to treat your input as signed, you'll want to test/js and print the unsigned absolute value (with a leading - if needed).

              – Peter Cordes
              Dec 30 '18 at 7:18











            • @PeterCordes, Hi, Peter! You're right about safety. It's a partial solution and I didn't think about signed numbers.

              – TigerTV.ru
              Dec 30 '18 at 17:09











            • You should still change idiv to div so it works for the full range of unsigned numbers. Hmm, actually this might be safe anyway, because 2^32-1 / 10 doesn't overflow EAX. zero-extending into edx:eax gives you a signed non-negative dividend from 0..2^32-1.

              – Peter Cordes
              Dec 30 '18 at 20:57













            • @PeterCordes, The idiv has been replaced. Also I added base for the number. What do you think about it? And else I reserved a buffer on stack for number string with size 32.

              – TigerTV.ru
              Dec 31 '18 at 1:13











            • add esp, 32 should be sub to reserve space. You're stepping on the caller's stack space. mov byte [ecx], 10 would be more efficient than setting a register first. Or even push 10 / mov ecx, esp / sub esp, 32. (For your current version, a large number with base=2 will use 32 digits, but you use up one of your 32 with a newline.)

              – Peter Cordes
              Dec 31 '18 at 1:25

















            You're using space below ESP. That's only safe in cases like this where you know there are no signal handlers installed, and shouldn't be used in functions that could be called in other contexts. 32-bit Linux doesn't guarantee a red-zone. Also, use xor edx,edx / div or cdq / idiv so the zero or sign-extension of the dividend matches the signedness of the division. In this case you want xor/div so you always have a positive remainder. If you want to treat your input as signed, you'll want to test/js and print the unsigned absolute value (with a leading - if needed).

            – Peter Cordes
            Dec 30 '18 at 7:18





            You're using space below ESP. That's only safe in cases like this where you know there are no signal handlers installed, and shouldn't be used in functions that could be called in other contexts. 32-bit Linux doesn't guarantee a red-zone. Also, use xor edx,edx / div or cdq / idiv so the zero or sign-extension of the dividend matches the signedness of the division. In this case you want xor/div so you always have a positive remainder. If you want to treat your input as signed, you'll want to test/js and print the unsigned absolute value (with a leading - if needed).

            – Peter Cordes
            Dec 30 '18 at 7:18













            @PeterCordes, Hi, Peter! You're right about safety. It's a partial solution and I didn't think about signed numbers.

            – TigerTV.ru
            Dec 30 '18 at 17:09





            @PeterCordes, Hi, Peter! You're right about safety. It's a partial solution and I didn't think about signed numbers.

            – TigerTV.ru
            Dec 30 '18 at 17:09













            You should still change idiv to div so it works for the full range of unsigned numbers. Hmm, actually this might be safe anyway, because 2^32-1 / 10 doesn't overflow EAX. zero-extending into edx:eax gives you a signed non-negative dividend from 0..2^32-1.

            – Peter Cordes
            Dec 30 '18 at 20:57







            You should still change idiv to div so it works for the full range of unsigned numbers. Hmm, actually this might be safe anyway, because 2^32-1 / 10 doesn't overflow EAX. zero-extending into edx:eax gives you a signed non-negative dividend from 0..2^32-1.

            – Peter Cordes
            Dec 30 '18 at 20:57















            @PeterCordes, The idiv has been replaced. Also I added base for the number. What do you think about it? And else I reserved a buffer on stack for number string with size 32.

            – TigerTV.ru
            Dec 31 '18 at 1:13





            @PeterCordes, The idiv has been replaced. Also I added base for the number. What do you think about it? And else I reserved a buffer on stack for number string with size 32.

            – TigerTV.ru
            Dec 31 '18 at 1:13













            add esp, 32 should be sub to reserve space. You're stepping on the caller's stack space. mov byte [ecx], 10 would be more efficient than setting a register first. Or even push 10 / mov ecx, esp / sub esp, 32. (For your current version, a large number with base=2 will use 32 digits, but you use up one of your 32 with a newline.)

            – Peter Cordes
            Dec 31 '18 at 1:25





            add esp, 32 should be sub to reserve space. You're stepping on the caller's stack space. mov byte [ecx], 10 would be more efficient than setting a register first. Or even push 10 / mov ecx, esp / sub esp, 32. (For your current version, a large number with base=2 will use 32 digits, but you use up one of your 32 with a newline.)

            – Peter Cordes
            Dec 31 '18 at 1:25


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f8194141%2fhow-to-print-a-number-in-assembly-nasm%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            Monofisismo

            Angular Downloading a file using contenturl with Basic Authentication

            Olmecas