Other I can't just print a sum in i386 assembler

Here is the program

Code:
segment .data

prompt1: db "Enter a number: ", 0       ; don't forget nul terminator
len1: equ $-prompt1
prompt2: db "Enter another number: ", 0
len2: equ $-prompt2
outmsg1: db "You entered: ", 0
len3: equ $-outmsg1



segment .bss

input1: resd 0
input2: resd 0



segment .text
        global _start
_start:

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        mov ecx, prompt1
        mov edx, len1 ; len
        int 80h

        mov eax, 3  ; read
        mov ebx, 0  ; stdin
        mov ecx, input1
        ;mov edx, 4  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        mov ecx, outmsg1
        mov edx, len3 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        mov ecx, input1
        ;mov edx, 4 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        mov ecx, prompt2
        mov edx, len2 ; len
        int 80h

        mov eax, 3  ; read
        mov ebx, 0  ; stdin
        mov ecx, input2
        ;mov edx, 4  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        mov ecx, outmsg1
        mov edx, len3 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        mov ecx, input2
        ;mov edx, 4 ; len
        int 80h

        mov eax, input1     ; eax = dword at input1
        mov ebx, input2     ; eax += dword at input2
        add eax, ebx
        mov ecx, eax
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        ;mov edx, 1 ; len
        int 80h

        ;Exiting
        mov eax, 1
        mov ebx, 0
        int 80h

Can you help me ?

Thank you
Didier
 
No experience at all with x86 assembly, but I would expect some code converting between (ascii) strings and numbers for that?

Also, if I interpret that correctly, reserving 0 bytes for inputs seems a bit fishy...
 
You need to learn assembly to be able to work with it correctly. this looks amateurish
 
Homework? This is not a linux or assembly language help group. AFAIK int 80h works (or used to) on Linux. Anyway, in general my advice would be to write a similar C program, compile with the -S flag to create an assembly output and learn from that. Do this on a i386 machine to generate assembly code for that.
 
Anyway, in general my advice would be to write a similar C program, compile with the -S flag to create an assembly output and learn from that.
Of course, only if it isn't homework. Otherwise, calling into libraries would be considered cheating and I guess you don't want to reproduce the whole printf() code in your answer 😈
 
Code:
mov eax, input1 ; eax = dword at input1 
mov ebx, input2 ; eax += dword at input2
add eax, ebx
input1 and input2 are pointers to the text you entered. You're going to need to convert that text to a number, then you can add those two numbers. All you are doing here is adding two pointers.
 
when you are working with pointers, or even if you need to debug something, in assembly. always have everything at your disposal. I ask you a question do you know what DWARF is
 
Hello

To compile the program under freebsd
nasm -f elf32 filename.asm
ld -m elf_i386_fbsd -o filename filename.o
sudo service linux onestart

brandelf -t Linux ./filename

./filename

Thank you
Didier
 
So you're actually looking for help with i386-assembly on Linux. Seems quite off-topic here.

Although this is just a detail in this context, you're clearly missing any distinction between pointers, ascii-encoded bytes and (32bit) numbers. Did you understand any of the answers you got?

edit: in machine language, anything is just bytes (or words consisting of bytes). Still, understanding how to interpret their content, based on what it should be, is really crucial for any assembler programming.
 
Calling convention is different too.
Calling convention is part of the ABI specification. So true but covered by ABI already. :)

If you're sticking to Linux ABI, well OK. To hunt the bugs down gdb is very handy tool. You can single step the program and see the registers each step - that can help you a lot during debugging. I'd say it's a must otherwise you're blind.

If you want to use this as calc you need to follow SirDice advise too. Not only you are adding pointers but those pointers point to a text, not numbers. I can input "asd" "dsa", you won't be able to add them together.

hint: ASCII numbers are from 0x30 - 0x39.
hint2: it's probably good idea to use functions in code as you'll be reusing the code
 
Sometime ago, I've replied to a thread, posting few 'FreeBSD-specific' hello-world style 'working' examples for fasm, as(1), nasm, and "embeded in C".
The only problem is that they run on a FreeBSD x64 machine, and quite frankly the last time I wrote anything for a i386 was with MASM 5.0 for DOS 5.0 and 6.22 — i.e. I can't remember anything! Still, look at the examples. They may give you some hints, maybe not — and that because changing a x64 code to x32 is not just about renaming RAX to EAX.

Here's the link:
 
You are reserving 0 doublewords with resd directive which is not what you want. In BSS all values are initialized to 0.
I'm not going to do the full homework for you but this is part of it. I did only one proof read of this during a boring telco at work so it may have some bugs and/or possibly cleaner code could be used. This program returns sum of digits of both numbers. I've prepped the addition part for you though I didn't use it in code on purpose. Edit: it was just one instruction missing, I put it there. It's up to you to come up with the printing routine though.
Code:
segment .data
    prompt: db "Enter a number: ", 0       ; don't forget nul terminator
    len: equ $-prompt

segment .bss
    nr1:    resd 1
    nr2:    resd 1
    buf:    resb 64

section .text
    global _start
_start:
main:
    call my_atoi
    mov [nr1], eax

    call my_atoi
    mov [nr2], eax

    mov edx, [nr1]
    add eax, edx

    mov ebx,eax
    mov eax,1
    int 0x80

; int my_atoi()
my_atoi:
    push esi
    push edi

    xor edi,edi        ; prep ret val

    ; write(1, prompt, len)
    mov eax, 4
    mov ebx, 1
    lea ecx, [prompt]
    mov edx, len
    int 0x80

    ; read(0, buf, 64)
    mov eax,3
    xor ebx,ebx
    lea ecx, [buf]
    mov edx, 64
    int 0x80

    test eax,eax        ; read() returned 0
    jz .Latoi_end

    cmp eax, -1        ; read() returned err
    je .Latoi_end

    mov edi,eax        ; current read bytes
    xor edx,edx        ; current check pos
    lea esi, [buf]
    cld

.Lcheck1:
    lodsb
    mov ebx,eax
    call isnum        ; isnum(nr)
    test eax, eax
    jz .Latoi_convert    ; not a num anymore

    inc edx
    cmp edx, edi        ; if (edx <= edi)
    jge .Latoi_convert

    cmp edx, 64        ; if (edx <= BUFSZ)
    jge .Latoi_convert
    jmp .Lcheck1

.Latoi_convert:
    xor edi, edi
    mov ecx, edx
    mov ebx, 1

.Latoi_convert.1:
    test ecx, ecx
    jz .Latoi_end
    mov al, [buf+ecx-1]    ; indexing from 0
    movzx eax,al
    sub eax, 0x30
    mul ebx
    add edi, eax

    xor edx,edx
    mov eax, 10
    mul ebx
    mov ebx, eax
    dec ecx
    jmp .Latoi_convert.1

.Latoi_end:
    mov eax, edi
    pop edi
    pop esi
    ret

; isnum(int nr)
isnum:
    xor eax,eax
    cmp bl, 0x30
    jb .Lisnum_end
    cmp bl, 0x39
    jg .Lisnum_end

    inc eax
.Lisnum_end:
    ret
 
+5 ¢
If we need to add two 64-bit unsigned numbers on i386 then we can use adc.
For instance, if the first number sits in edx (high 32 bits) and eax (low 32 bits) and the second number sits in ebx (high 32 bits) and ecx (low 32 bits),
then we can add them something like this:

Code:
add eax, ecx    ; adding low parts
adc edx, ebx   ; adding high parts, take CF into account
 
True. But then printing 64b number in decimal on 32b machine is an interesting problem. If this is homework then I think that problem alone is harder than the original homework.
 
  • Like
Reactions: _al
True. But then printing 64b number in decimal on 32b machine is an interesting problem. If this is homework then I think that problem alone is harder than the original homework.
And also parsing the two input numbers! That is why I had suggested writing a C program first. It would also help if the OP wrote down a definition of the problem he is trying to solve. Being able to write a clear problem definition is quite useful. And you can continue to add more notes to it as you learn more about the properties of the solution, without tying yourself up in the coding details (especially if you are new to it).
 
but easy to write everything in assembly, first he has to know what he really wants.
 
Hello

I don't understand why when there are two read input1 and input2 the input1 ends up with the two values of input1 first input and input2 second input.


Thank you
Didier



Code:
        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt1]
        mov edx, len1 ; len
        int 80h

        mov eax, 3  ; read
        mov ebx, 0  ; stdin
        lea ecx, [input1]
        mov edx, 10  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [outmsg1]
        mov edx, len4 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input1]
        mov edx, 10 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt2]
        mov edx, len2 ; len
        int 80h

        mov eax, 3  ; read
        mov ebx, 0  ; stdin
        lea ecx, [input2]
        mov edx, 10  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [outmsg1]
        mov edx, len3 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input2]
        mov edx, 10 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt9]
        mov edx, len9 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input1]
        ;mov edx, 10  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt8]
        mov edx, len8 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input2]
        ;mov edx, 10  ; len
        int 80h

        ;Exiting
        mov eax, 1
        mov ebx, 0
        int 80h


here is the output
Code:
# ./third-PB-Read 
Enter a number: 128
You entered: 128
Enter another number: 150
You entered: 150
Contains input1: 128
150
Contains input2: 150
 
Last edited by a moderator:
You didn't share the whole program so we don't know how you defined the variables. You're reading by 10 bytes so I'm not sure how you even get that clean output (meaning after first "Enter a number:" syscall read expects 10 bytes of data in not interrupted by eof (ctrl+d)).

This is a good time for you to get familiar with the debugger such as gdb and do a step by step debugging to see what's wrong (google gdb tutorials). It's also good to know what is program and how does it look like in memory. In my opinion this is a great article: Anatomy of a Program in Memory. While not aimed for FreeBSD same principles apply.
 
Here is the full program

Code:
segment .data

prompt1: db "Enter a number: ", 0
len1: equ $-prompt1
prompt2: db "Enter another number: ", 0
len2: equ $-prompt2
outmsg1: db "You entered: ", 0
len3: equ $-outmsg1
outmsg2: db "The sum is: ", 0
len4: equ $-outmsg2
prompt1size1: db "Enter a size of number < 10 for size1: ", 0
len1size1: equ $-prompt1size1
prompt2size2: db "Enter another size of number < 10 for size2: ", 0
len2size2: equ $-prompt2size2
prompt9: db "Contains input1: ", 0
len9: equ $-prompt9
prompt8: db "Contains input2: ", 0
len8: equ $-prompt8
nl: db 10

segment .bss

input1: resb 10
input2: resb 10

segment .text
        global _start
_start:


        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt1]
        mov edx, len1 ; len
        int 80h

        mov eax, 3  ; read
        mov ebx, 0  ; stdin
        lea ecx, [input1]
        mov edx, 10  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [outmsg1]
        mov edx, len4 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input1]
        mov edx, 10 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt2]
        mov edx, len2 ; len
        int 80h

        mov eax, 3  ; read
        mov ebx, 0  ; stdin
        lea ecx, [input2]
        mov edx, 10  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [outmsg1]
        mov edx, len3 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input2]
        mov edx, 10 ; len
        int 80h


        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt9]
        mov edx, len9 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input1]
        ;mov edx, 10  ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [prompt8]
        mov edx, len8 ; len
        int 80h

        mov eax, 4  ; write
        mov ebx, 1  ; stdout
        lea ecx, [input2]
        ;mov edx, 10  ; len
        int 80h

        ;Exiting
        mov eax, 1
        mov ebx, 0
        int 80h

Thank you
Didier
 
Last edited by a moderator:
There are handful of good tips on how to proceed here you didn't acknowledge nor took to the heart.
Code:
mov eax, 4  ; write
mov ebx, 1  ; stdout
lea ecx, [input2]
;mov edx, 10  ; len
int 80h
While shaving off bytes in shellcode has its place it's definitely not here. You are not setting edx (number of bytes to print aka len) and hence you are printing more than one variable.

This mistake is easy to spot in gdb. But even truss(1) is good enough here:
Code:
$ truss ./hello
Enter a number: write(1,"Enter a number: \0",17)         = 17 (0x11)
AA
read(0,"AA\n",10)                 = 3 (0x3)
You entered: write(1,"You entered: ",13)             = 13 (0xd)
AA
write(1,"AA\n\0\0\0\0\0\0\0",10)         = 10 (0xa)
Enter another number: write(1,"Enter another number: \0",23)         = 23 (0x17)
BB
read(0,"BB\n",10)                 = 3 (0x3)
You entered: write(1,"You entered: \0",14)             = 14 (0xe)
BB
write(1,"BB\n\0\0\0\0\0\0\0",10)         = 10 (0xa)
Contains input1: write(1,"Contains input1: \0",18)         = 18 (0x12)
AA
BB
write(1,"AA\n\0\0\0\0\0\0\0BB\n\0\0\0\0\0",18)     = 18 (0x12)                    ; <-- here you can see you're printing more than size of input
Contains input2: write(1,"Contains input2: \0",18)         = 18 (0x12)
BB
write(1,"BB\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0"...,18) = 18 (0x12)
linux_exit(0x0)
process exit, rval = 0
$
There are some other consideration in the code but we did address them here already before.
 
Back
Top