1

My code below, for some reason only outputs the last 2 digits of the number, regardless of how long the umber is... Can someone please tell me the issue/how to fix? Of course I want to print out the whole number, but it isn't letting me. please help, thank you

global _start

section .text
_start:
    mov eax, 6789       ; The number to be printed
    mov ebx, 0          ; count the digits
    mov ecx, 10         ; divisor

divide:
    mov edx, 0
    div ecx             ; divide the number into eax and edx | for 6789, eax = 678, edx = 9
    push ebx            ; push current count into the stack
    inc ebx             ; increase the number of digits
    push edx            ; push the value of remainder into the stack
    cmp eax, 0          ; check if eax = 0, means all digits are pushed into the stack
    jne divide

; Stack at the end of divide: (entry from left): 6, 3, 7, 2, 8, 1, 9, 0 ]
print:
    pop edx             ; take out the value pushed previously in the stack
    add edx, 0x30       ; Convert to ASCII
    mov [digit], edx    ; Save the value of edx to digit
    mov eax, 4          ;\
    mov ebx, 1          ; |---> use sys_write to print on screen
    mov ecx, digit      ; |
    mov edx, 1          ;/
    int 0x80

    pop ebx             ; Restore value of count to ebx from the stack
    cmp ebx, 0          ; compare whether count is equal to 0
    jnz print           ; if not 0, go back to print and print the next digit on the screen


concl:
    mov eax, 1
    mov ebx, 0
    int 0x80


section .data
    digit db 0

I have used gdb-(GEF) for debugging and the stack seems to be functioning properly, same with all the registers.

An example output would be for the number: 6789 The output is: 89

Aleph_0
  • 15
  • 4
  • 1
    You have two pops in your print loop, because you're trying to use EBX for both a loop counter and for the first arg to `write`. Pick a different reg; you aren't using ESI or EDI for anything. Also, if you're going to do a 4-byte store (`mov [digit], edx`), reserve 4 bytes there, not just 1. Or better, store backwards into a buffer so you only need one loop, and only make one write call. [How do I print an integer in Assembly Level Programming without printf from the c library?](https://stackoverflow.com/a/46301894) or [Add 2 numbers and print](https://stackoverflow.com/a/28524951) – Peter Cordes Nov 13 '22 at 13:59

1 Answers1

1

A bad case of line continuation

mov [digit], edx    ; Save the value of edx to digit
mov eax, 4          ;\
mov ebx, 1          ; |---> use sys_write to print on screen
mov ecx, digit      ; |
mov edx, 1          ;/

Don't inadvertently put a backslash character at the end of a line because the assembler will consider it to be the signal for line continuation, which means that the line that follows gets stitched to the current line, and in your case it produces this:

mov [digit], edx    ; Save the value of edx to digit
mov eax, 4          ;    mov ebx, 1          ; |---> use sys_write to print on screen
mov ecx, digit      ; |
mov edx, 1          ;/

The part that loads EBX with the reference to STDOUT is now behind the semicolon and became a mere comment in the program. You won't find it in the executable file. The print loop will be using whatever happens to be in EBX.

In your test run with the number 6789, the first 2 iterations of the print loop were using EBX=4 and EBX=3, but the last 2 iterations were using EBX=2 and EBX=1. Now STDERR=2 and STDOUT=1, and both write to the screen. That's why you only ever got output for the last 2 digits.

Notwithstanding that you should write mov [digit], dl instead of mov [digit], edx, the code seems correct. Your unusual choice to double push is matched by double pop, so that is fine. You just need to remove that unlucky \

Sep Roland
  • 33,889
  • 7
  • 43
  • 76
  • 1
    Debugging techniques that would have caught this include `strace`. And single-stepping with a debugger in disassembly (not source) mode; you'd hopefully notice that the `mov ebx, 1` was missing. It would also be easier to spot if they used a separate register for the loop counter instead of inefficiently alternating loop counter and data. But yes, that is apparently correct, just nasty. Fascinating coincidence that this combination of design choices and comment bug created this FD=counter situation with those symptoms. – Peter Cordes Nov 13 '22 at 23:11
  • Wow, I actually can't believe that the '\' was the problem! I feel so stupid for not knowing this... Even though i started assembly yesterday. Thank you! – Aleph_0 Nov 14 '22 at 07:30