1

I'm a beginner in Linux assembler and I have some questions. I'd like to read some characters from keyboard, convert it to value (I understand that this convertion should be from ASCII to decimal, right?), do some math (add, sub, multiply, whatever) and display the result in Terminal. How should I do that? I wrote some code but it probably doesn't make sense:

SYSEXIT = 1
EXIT_SUCC = 0
SYSWRITE = 4
SYSCALL = 0x80
SYSREAD = 3

.data
value: .space 5, 0
value_len: .long .-value

result: .long
result_len: .long .-result

.text
.global _start

_start:


movl $SYSREAD, %eax
movl $EXIT_SUCC, %ebx
movl $value, %ecx
movl value_len, %edx
int $SYSCALL

movl $0, %edx
movl value_len, %ecx

for:                            
    movb value(, %edx, 1), %al
    subb $48, %al
    movb %al, result(, %edx, 1)
    inc %edx    
loop for    

add $10, result

movl $0, %edx
movl result_len, %ecx

for1:                           
    movb result(, %edx, 1), %al
    add $48, %al
    movb %al, result(, %edx, 1)
    inc %edx    
loop for1

movl $SYSWRITE, %eax            
movl $SYSEXIT, %ebx 
movl $result, %ecx
movl result_len, %edx
int $SYSCALL

movl $SYSEXIT, %eax
movl $EXIT_SUCC, %ebx
int $SYSCALL

I don't know if I should reserve memory by spaces? Or reading characters in loop? How to convert it, to be able to make some math operation and then convert it to be able to display it? I know that to get the value of ASCII char I should subtract 48, but what next? I had an idea to multiply each bits by 2^k where k is 0,1,2...n it's good idea? If so, how to implement something like this?

As you can see I had a lot of questions, but I only need to someone show me how to do, what I am asking about. I saw some similar problems, but nothing like this in Linux.

Thank you in advance for the all information. All the best.

Paul R
  • 208,748
  • 37
  • 389
  • 560
user3448282
  • 2,629
  • 3
  • 25
  • 47
  • 1
    The canonical advice for this type of problem is: (i) write the code in C, (ii) get it working properly, (iii) generate assembler source (`gcc -Wall -O3 -S ...`), (iv) use the generated source either "as is" or as a template or starting point for your own code. – Paul R Mar 21 '14 at 22:40
  • In addition to what Paul said, you will save yourself considerable headache if you use the C library to make system calls, rather than hand-coding them. And `strtol` and `printf` will still be your friends as well. – zwol Mar 21 '14 at 22:47
  • Thanks for tip :) I will try it and I back here if I have some problems. – user3448282 Mar 21 '14 at 23:11
  • BTW `movl $SYSEXIT, %ebx` in writing is definitely wrong. Yes, the value here shall be 1 (under usual circumstances) but it really is `STDOUT_FILENO`, not a syscall number. – Netch Mar 22 '14 at 05:45
  • I tried to code it in C, and then I generated assembler source, but I don't get it. It's too complicated can someone try to show me how to do this properly? – user3448282 Mar 22 '14 at 11:25

1 Answers1

0

At first reading and writing the console in Linux is by using the file functions with special console handles, that have always the same values: STDIN=0, STDOUT=1 and STDERR=2.

At second you will need some decent documentation about Linux system calls. Notice that the C-centric one (like "man") are not suitable, because C language does not use the system calls directly, but has wrappers that often change the arguments and the result values.

On the following site you can download an assembly-centric SDK for Linux, that contains the needed documentation and many examples and include files.

If you only need the help files, you can browse them online: Here

If the problem is the conversion from ASCII string to number and then back to string, here are two simple procedures that can do the job, if the requirements are not so big. The StrToNum is not so advanced, it simply convert decimal unsigned number:

    ; Arguments:
    ;   esi - pointer to the string
    ; Return:
    ;   CF=0
    ;   eax - converted number
    ;   edx - offset to the byte where convertion ended.
    ;
    ;   CF=1 - the string contains invalid number.
    ;
    StrToNum:
            push    ebx esi edi
            xor     ebx,ebx         ; ebx will store our number

            xor     eax,eax
            mov     al,[esi]
            cmp     al,'0'
            jb      .error
            cmp     al,'9'
            jbe     .digit
            jmp     .error
         .digit:
            sub     al,'0'
            add     ebx,eax
            inc     esi
            mov     al,[esi]
            cmp     al,'0'
            jb      .finish
            cmp     al,'9'
            ja      .finish
            mov     edx,ebx         ; multiply ebx by 10
            shl     ebx,3
            add     ebx,edx
            add     ebx,edx
            jmp     .digit
         .finish:

            mov     eax, ebx
            mov     edx, esi
            clc
            pop     edi esi ebx
            ret

         .error:
            stc
            pop     edi esi ebx
            ret

NumToStr is pretty flexible. It converts number to a string in any radix and with sign:

    ;**********************************************************************************
    ; NumToStr converts the number in eax to the string in any radix approx. [2..26]
    ; Arguments:
    ;   edi - pointer to the string buffer
    ;   ecx - radix
    ;   eax - number to convert.
    ; There is no parameter check, so be careful.
    ; returns: edi points to the end of a converted number
    ;**********************************************************************************
    NumToStr:
        test  eax,eax
        jns   NumToStrU
        neg   eax
        mov   byte [edi],"-"
        inc   edi

    NumToStrU:
        cmp   eax,ecx
        jb    .lessA
        xor   edx,edx
        div   ecx
        push  edx
        call  NumToStrU
        pop   eax

    .lessA:
        cmp   al, 10
        sbb   al, 69h
        das
        stosb
        ret
johnfound
  • 6,857
  • 4
  • 31
  • 60
  • If you want to avoid `imul` for multiplying by 10, the optimal way is to multiply by 5 using `lea`, and then by 2 using `add`. You can even fold the addition of the new digit (`total = total*10 + digit`) into two LEAs, as in [NASM Assembly convert input to integer?](https://stackoverflow.com/a/49548057) - in your case, `lea ebx, [ebx*4 + ebx]` (times 5) `lea ebx, [ebx*2 + eax]`. This `x * 2 * 5` or `x * 5 * 2` doesn't need an extra register. – Peter Cordes Mar 02 '23 at 21:38