1

MY objective is to collect the digits in a string and print only them. In the end i wish to add them together to return a result, but for now i am stuck at trying to collect them.

I am totaly new to assembly in general (3 hours in) i am a computer science student, we are asked to use NASM assembly with intel syntax and we can't use c library command. I tried to write a code but it turn for some time and then return Timeout:

section .data
    message db 'Hell34o, w2or5ld', 0
    digits db '0123456789'

section .text
    global _start

_start:
    ; Traverse the string
    mov eax, message ; Address of the string
    mov ebx, digits ; Address of the digits
    mov ecx, 0 ; Index of the next digit occurrence
    mov edx, 0 ; Number of digits found

loop:
    mov al, byte [eax] ; Load the next character of the string
    cmp al, 0 ; Check if it is the end-of-string character
    je done ; If yes, exit the loop
    mov edi, ebx ; EDI = address of the digits
    mov ecx, 0 ; ECX = 0

next_digit:
    mov dl, byte [edi+ecx] ; Load the next digit
    cmp dl, 0 ; Check if it is the end-of-string character
    je skip ; If yes, move to the next digit
    cmp al, dl ; Compare the character with the digit
    jne next_digit ; If different, try the next digit
    ; If we are here, then we have found a matching digit
    mov byte [eax], dl ; Replace the character with the digit in the string
    inc eax ; Move to the next position in the string
    inc edx ; Increment the count of digits found
    jmp loop ; Go back to the beginning of the loop

skip:
    inc ecx ; Move to the next digit in the digit table
    jmp next_digit ; Search for the next digit

done:
    ; Display the found digits
    mov eax, 4 ; Code for the sys_write function
    mov ebx, 1 ; File descriptor for stdout
    mov ecx, message ; Address of the string (now with only digits)
    mov edx, edx ; Number of digits found
    int 0x80 ; System call to display the string

; End the program
    mov eax, 1           ; Code for the sys_exit function
    xor ebx, ebx         ; Return code 0
    int 0x80             ; System call to end the program

I am developing on Linux, if someone could point me toward a solution it would be appreciated i find assembly challenging.

Weather Vane
  • 33,872
  • 7
  • 36
  • 56
isaac
  • 11
  • 2
  • 3
    Note that generally digit characters are encoded in ascending consecutive sequence, so you can check if a character is a digit with the assembler equivalent of `if(ch >= '0' && ch <= '9')` – Weather Vane Feb 28 '23 at 20:33
  • 3
    Note too that a) your `digits` array does not have a `0` terminator and b) when you `jne next_digit` nothing has changed: the loop is infinite. – Weather Vane Feb 28 '23 at 20:36
  • 1
    *it turn for some time and then return Timeout:* - Are you running it online or something? Run your code locally (in a VM or WSL2 if you don't have a Linux machine) so you can use a debugger to single-step. This is *huge* for assembly, seeing your code run one instruction at a time and watching registers change will show you what's happening in vastly more detail than the fact that there was an infinite loop somewhere. See the bottom of https://stackoverflow.com/tags/x86/info for asm GDB tips. – Peter Cordes Mar 01 '23 at 10:51

1 Answers1

0
mov al, byte [eax] ; Load the next character of the string
mov dl, byte [edi+ecx] ; Load the next digit

Your code is using EAX for an address and EDX for a counter. The above loads are destroying the address as well as the counter! See How do AX, AH, AL map onto EAX? to see how AL is the lowest 8 bits of EAX and DL is the lowest 8 bits of EDX.

  cmp dl, 0 ; Check if it is the end-of-string character
  je skip ; If yes, move to the next digit
  ...
skip:
  inc ecx ; Move to the next digit in the digit table
  jmp next_digit ; Search for the next digit

I can't follow the logic here. Why would you 'move to the next digit' once you found the 'end of the string with digits'? The inc ecx that you do, will bring you outside of the string memory.

mov byte [eax], dl ; Replace the character with the digit in the string

This will write the digit right where it was read, not very useful!
Apparently you wish to place the collected digits in a condensed manner at the message label. For that you need a separate pointer. You can't use EAX since that's already used for reading from the original message.

digits db '0123456789'

Notwithstanding @WeatherVane's comment about the digit characters being encoded in an ascending consecutive sequence, so you could write a far better code, your approach can work too. What is causing you troubles (like an infinite loop), is that you are using a whopping 3 registers (EBX, ECX, EDI) to deal with that digits list and that you forgot to zero-terminate the list.


You don't need to tally the number of digits in some register. The difference between the address behind the last collected digit and the address where the first collected digit got stored gives you that information.

mov  edx, edi
sub  edx, message       ; Number of digits found

Next is what it could look like (using your approach):

section .data
    message db 'Hell34o, w2or5ld', 0
    digits  db '0123456789', 0

section .text
    global _start

_start:
    mov  esi, message    ; ESI is pointer for reading stringcharacters
    mov  edi, esi        ; EDI is pointer for writing digits
loop:
    mov  al, byte [esi]
    inc  esi
    cmp  al, 0
    je   done
    mov  ebx, digits
next_digit:
    mov  dl, byte [ebx]
    inc  ebx
    cmp  dl, 0
    je   loop
    cmp  al, dl
    jne  next_digit
    mov  byte [edi], al
    inc  edi
    jmp  loop

done:
    mov  eax, 4
    mov  ebx, 1
    mov  ecx, message
    mov  edx, edi
    sub  edx, ecx        ; Number of digits found
    int  0x80
Sep Roland
  • 33,889
  • 7
  • 43
  • 76