Search code examples
assemblyx86printfnasmexponentiation

Can't figure out printf function in assembly x86 and working with operands


I'm already nervous about posting this question, but here it goes. Im attempting to design an Assembly Program to take in two integers, then take in an operand (*, +, or ^). Then, depending on the operand, the program will perform the arithmetic sequence based on the operand chosen. The output has to look exactly like this, lets say the user inputs 5, then the user inputs 6, and lastly the user inputs a *, the program must print out

OP 5 * 6 = 30

Now, I cannot grasp the concept of printf for some reason, so my printfunction at the bottom is my ridiculous way of attempting to print this out. If someone could explain to me how printf works, id love to hear it! I have very basic knowledge of the stack. Also, I do not have the exponential function in this, because I have no idea how to do it in assembly language. And lastly, I have a non program related question for the true computer gods out there...I absolutely hate assembly language, I have trouble writing basic operations in this language. I loved working in C, CPP, and Java...is this langauge absolutely necessary to survival in a programmers day to day, or is this a history lesson on how people made fire before they had lighters? Anyway, any answers to any questions are welcome, and thank you in advance.

;program to add, multiply, or give the power of a number

%include "asm_io.inc"


segment .data 


prompt1 db    "Enter a number: ", 0        ;prompts
prompt2 db    "Enter another number: ", 0
prompt3 db    "Enter an operand", 0
prompt4 db    "OP ", 0    ;idiotic prompts for printing
prompt5 db    " = ", 0    ;another printing prompt

segment .bss

num1  resd 1    ;variable for 1st number
num2  resd 1    ;variable for 2nd number
op    resd 1    ;variable for operand


segment .text

    global  asm_main
asm_main:
    enter   0,0               ; setup routine
    pusha

    restart:
        mov     eax, prompt1      ; print out prompt
        call    print_string
        call    print_nl

        call    read_int          ; read integer
        mov     [num1], eax       ; store into num1
        call    print_nl

        mov     eax, prompt2      ; print out prompt
        call    print_string
        call    print_nl

        call    read_int          ; read integer
        mov     [num2], eax     ; store into num2
        call    print_nl

        mov     eax, promtp3    ;print out prompt
        call    print_string
        call    print_nl

        call    read_char       ;read operand and dispose of null
        call    read_char
        mov     [op], eax       ;store operand in [op]
        call    print_nl

        cmp     [op], '*'       ;operand comparison
        jne     jmp1
        call    mulFun
        jmp     restart

jmp1:   cmp     [op], '+'       ;operand comparison
        jne     jmp2
        call    sumFun
        jmp     restart

jmp2:   cmp     [op], '^'       ;operand comparison
        jne     jmp3
        call    expFun
        jmp     restart

jmp3:   cmp     [op], 'e'       ;exit function
        je      end1

end1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    call    print_nl          ; pr
    popa
    mov     eax, 0            ; return back to C
    leave
    ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mulfun:                     ;multiplication function
    mov     ebx, [num1]
    mov     ecx, [num2]
    imul    ebx, ecx
    jmp     printFun

sumFun:                     ;sum function
    mov     ebx, [num1]
    mov     ecx, [num2]
    add     ebx, ecx
    call    printFun


printFun:                   ;printing function
    mov     eax, [prompt4]
    call    print_string
    mov     eax, [num1]
    call    print_string
    mov     eax, [op]
    call    print_string
    mov     eax, [num2]
    call    print_string
    mov     eax, [prompt5]
    call    print_string
    mov     eax, ebx
    call    print_string
    call    print_nl
    ret

Solution

  • Everywhere I found an issue I have added *** in the comments. A few things to note:

    • You had typos in some of your labels
    • NASM is case sensitive, so mulfun is not the same as mulFun.
    • If you have an instruction taking one or more operands that doesn't involve a register (for src or destination) but references memory - you need to specify the size of the memory operand. For example cmp [op], '+' the size of the data [op] refers to has to be specified so you prefix it with the size. Size can be byte, word, dword. You are comparing a single character so the size would be byte . The code should have looked like this cmp byte [op], '+'
    • If you have a variable and you do mov eax, varname this moves the address of varname to EAX. If you want to move the contents of varname you have to surround it with square brackets like mov eax, [varname] . When dealing with string addresses and the print_string routine you need to pass the address of the string in EAX, not the contents. So leave out the brackets.
    • If you use call to call a function, your function should end with a ret.
    • Don't jmp to a function, use call
    • If you want to print a character don't use print_string, use print_char. Place the character in EAX
    • If you want to print an integer don't use print_string, use print_int. Place the integer in EAX

    The revised code is as follows:

    ;program to add, multiply, or give the power of a number
    
    %include "asm_io.inc"
    
    segment .data
    
    prompt1 db    "Enter a number: ", 0        ;prompts
    prompt2 db    "Enter another number: ", 0
    prompt3 db    "Enter an operand", 0
    prompt4 db    "OP ", 0    ;idiotic prompts for printing
    prompt5 db    " = ", 0    ;another printing prompt
    
    segment .bss
    
    num1  resd 1    ;variable for 1st number
    num2  resd 1    ;variable for 2nd number
    op    resd 1    ;variable for operand
    
    
    segment .text
    
        global  asm_main
    asm_main:
        enter   0,0                 ; setup routine
        pusha
    
        restart:
            mov     eax, prompt1    ; print out prompt
            call    print_string
            call    print_nl
    
            call    read_int        ; read integer
            mov     [num1], eax     ; store into num1
            call    print_nl
    
            mov     eax, prompt2    ; print out prompt
            call    print_string
            call    print_nl
    
            call    read_int        ; read integer
            mov     [num2], eax     ; store into num2
            call    print_nl
    
            mov     eax, prompt3    ;print out prompt
                                    ;*** Typo - promtp3 changed to prompt3
            call    print_string
            call    print_nl
    
            call    read_char       ;read operand and dispose of null
            call    read_char
            mov     [op], eax       ;store operand in [op]
            call    print_nl
    
            cmp     byte [op], '*'  ;operand comparison
                                    ;*** We must specify the size of data we are
                                    ;*** comparing, so we tell the assembler that
                                    ;*** with 'byte' in front of the variable
            jne     jmp1
            call    mulFun
            jmp     restart
    
    jmp1:   cmp     byte [op], '+'  ;operand comparison
                                    ;*** We must specify the size of data we are
                                    ;*** comparing, so we tell the assembler that
                                    ;*** with 'byte' in front of the variable
            jne     jmp2
            call    sumFun
            jmp     restart
    
    jmp2:   cmp     byte [op], '^'  ;operand comparison
                                    ;*** We must specify the size of data we are
                                    ;*** comparing, so we tell the assembler that
                                    ;*** with 'byte' in front of the variable
            jne     jmp3
    ;        call    expFun         ;*** This expFun function doesn't exist so
                                    ;*** don't call it so we can compile and link
            jmp     restart
    
    jmp3:   cmp     byte [op], 'e'  ;exit function
                                    ;*** We must specify the size of data we are
                                    ;*** comparing, so we tell the assembler that
                                    ;*** with 'byte' in front of the variable
            je      end1
    
    end1:
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        call    print_nl          ; pr
        popa
        mov     eax, 0            ; return back to C
        leave
        ret
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    mulFun:                     ;multiplication function
                                ;*** NASM is case sensitive - changed mulfun to mulFun
        mov     ebx, [num1]
        mov     ecx, [num2]
        imul    ebx, ecx
        call    printFun        ;*** Call printFun, don't 'jmp' to it
        ret                     ;*** Since mulfun was called, we use 'ret' to return
    
    sumFun:                     ;sum function
        mov     ebx, [num1]
        mov     ecx, [num2]
        add     ebx, ecx
        call    printFun
        ret
    
    printFun:                   ;printing function
        mov     eax, prompt4    ;*** We want the address of prompt4, not what is at prompt4
                                ;*** Remove the brackets from [prompt4]
        call    print_string
        mov     eax, [num1]
        call    print_int       ;*** Use print_int to print an integer, not print_string
        mov     eax, [op]
        call    print_char      ;*** Use print_char to print a char, not print_string
        mov     eax, [num2]
        call    print_int       ;*** Use print_int to print an integer, not print_string
        mov     eax, prompt5    ;*** We want the address of prompt5, not what is at prompt5
                                ;*** Remove the brackets from [prompt5]
        call    print_string
        mov     eax, ebx
        call    print_int       ;*** Use print_int to print an integer, not print_string;
        call    print_nl
        ret
    

    I will leave it up to the original poster to develop the expFun function. For the time being I have commented it out so the existing code can be assembled, linked, and run.

    You can use printf but I think the long way can teach a few things too, and I have excluded a discussion of printf from my answer. Your instructor, course material, teacher assistant would be a good place to start with your other questions.

    This answer is being provided to get your program into a usable state so that you can proceed with the assignment. In my opinion the original question is too broad. If further help is needed it is probably best to ask a new question with a specific issue.