CSC231 2-Hour Crash Course

From dftwiki3
Revision as of 15:42, 5 March 2011 by Thiebaut (talk | contribs) (On Fedora)
Jump to: navigation, search

--D. Thiebaut 15:00, 4 March 2011 (EST)


This lab assumes that you have the open-source nasm assembler available and that you are working under Linux or Mac OS X. The one-evening assembly crash course is meant to present assembly language concepts on the Pentium as a preparation for writing assembly language programs in Hexadecimal for the 6801 HeathKit.



Note: Information about how to make nasm, ld, and gcc work together is provided in the Sys-Admin section at the end...



The architecture of the Pentium

  • Registers
    • EAX, EBX, ECX, EDX
    • ESI, EDI
    • EIP
    • ESP, EBP

Login

  • Login to Hadoop0

Simple I/O in assembly

Get a copy of the following programs:

Exercise #1:

Assemble, link and run the program.

  nasm -f elf asm_io.asm        (do this only once for all the exercises)
  nasm -f elf prog1.asm
  gcc -o prog1 -m 32 driver.c prog1.o asm_io.o
 ./prog1
   

Basic instructions and operands

        section .data
a       dd      3
b       dd      5
result  dd      0


        section .text
        global  asm_main
asm_main:       
        mov     eax,[a]
        add     eax,[b]
        mov     [result],eax
        
        mov     eax,[result]          ; pass result to print_int
        call    print_int             ; and print value

Exercise #2

Create and run the program. Verify that it outputs the sum of the two variables


Exercise #3

Modify the program so that it computes the sum of 5 variables containing the numbers 3, 5, 8, 10, and 20. Your program should output this sum.


Addressing Modes

we can access memory using the address of a variable plus an offset:

          a       dd       3
          b       dd       5
          ...
          ; sum up two variables in eax
          mov     eax, [a]
          add     eax, [b]

          ; can also be written as 
          mov     eax, [a]
          add     eax, [a+4]
      


When dealing with an array of several values, it's easier to use an index, either ESI, or EDI.


          table    dd      3, 5, 8, 10, 20
          result   dd      0

          mov      esi,table    ; esi gets address of table variable
          mov      eax,[esi]    ; get first dword of table in eax
          add      esi, 4       ; make esi point to next dword
          add      eax, [esi]   ; add second dword of table to eax
          add      esi, 4       ; make esi point to third dword
          add      eax, [esi]   ; add third dword to eax
          add      esi, 4       ; esi points to 4th dword
          add      eax, [esi]   ; add 4th dword to eax
          add      esi, 4       ; esi points to last dword
          add      eax, [esi]   ; add last dword to sum
          mov      [result],eax ; save sum in variable result
      

If needed, we can use and offset along with the index. Here's another way of summing up two variables:

          a        dd     3
          b        dd     5
          result   dd     0
          ...
          mov      esi, a       ; make esi point to a
          mov      eax, [esi]   ; get 1st variable
          add      eax, [esi+?] ; figure out what number to use!
          mov      [esi+?],eax  ; store result.  Figure out the offset!


Exercise #4

Write the program that will store the first five fibonacci numbers in the array table defined as:

          table    dd     1, 1, 0, 0, 0

The final content of the table should be 1, 1, 2, 3, 5. Your program should use the recurrence equation:

 Fibn = Fibn-1 + Fibn-2.

Loops

Loops can easily be implemented: store the number of times you need to repeat a block of code in ecx, and prefix the first instruction of the block with a label, as follows:

                    mov    ecx, 5        ; get ready to loop 5 times
                    mov    eax, 1        ; start with 1 in eax
          repeat:   call   print_int     ; print eax to the screen
                    add    eax, 2        ; add 2 to eax
                    loop   repeat        ; repeat 5 times


Exercise #5

Rewrite the program that sums up the 5 numbers in the array table using a loop.


Tests

Tests can be used to compare quantities and to perform a two-way branch depending on the result.


               cmp    eax, 3           ; compare eax to 3
               jne    there            ; if they are not equal, go to "there"
               mov    eax, msg1        ; otherwise print msg1
               call   print_string
               jmp    done             ; skip over next 2 instructions
       
      there:   mov    eax, msg2        ; print msg2
               call   print_string
      done:    ...                     ; end up here in both cases


If eax contains a value different from 3, the code above prints whatever string is at address msg2, otherwise, if eax is 3, the code prints the contents of msg1.

Exercise #6

Assume that you have an array of 10 numbers, write the code that will print only the numbers that are different from 0.


        table    dd      0, 1, 0, 10, 11, 4, 0, 0, 100, 0


Functions

Functions work in a way similar to the functions used in higher level language, except that there isn't a natural way to pass parameters. Parameters are typically passed in registers (by preloading the eax, ebx, ecx, or edx registers before the call), or by pushing them in the stack before calling the function. For today, we'll look only at passing parameters via registers. Let's write a program that uses a function to which we pass two integers, say 3, and 5, and the function outputs:

the sum of 3 and 5 is 8

If we pass it two new values, say 10, and 20, it will output

the sum of 10 and 20 is 30

        section .text
        global  asm_main

   ;;; -----------------------------------------------------------
   ;;; sumfunc: ebx and ecx are assumed to contain 2 integers that
   ;;;          this function will add together, and display 
   ;;;          a string of the form "the sum of x and y is z"
   ;;;          msg1, msg2, and msg3 are 3 strings declared in the
   ;;;          data segments
   ;;; -----------------------------------------------------------
   sumfunc:     mov    eax, msg1      ; "the sum of "
                call   print_string

                mov    eax, ebx       ; print int in ebx
                call   print_int 

                mov    eax, msg2      ; " and "
                call   print_string

                mov    eax, ecx       ; print int in ecx
                call   print_int

                mov    eax, msg3      ; " is "
                call   print_string

                ...                   ; figure out what 3 instructions
                ...                   ; are necessary to print ebx plus
                ...                   ; ecx
                call   print_nl       ; print new-line character
                ret

   asm_main:
                mov   ebx, 3
                mov   ecx, 5
                call  sumfunc         ; prints "the sum of 3 and 5 is 8"

                mov   ebx, 10
                mov   ecx, 20
                call  sumfunc         ; prints "the sum of 10 and 20 is 30"
    

Exercise #7

Assume that we have two arrays of integers, A, and B. A has 5 integers. B has 10 integers. Write a function to which we can pass an array and the number of integers it contains, and the function displays only the numbers of the array that are not zero.

A       dd      1, 0, 2, 0, 5
B       dd      1, 0, 0, 3, 1, 2, 0, 0, 9, 7


Solutions

prog1.asm prog2.asm prog3.asm prog4.asm prog5.asm prog6.asm prog7.asm

Information for the Sys-Admin

  • To make nasm, ld, and gcc work together, we have to stay in 32-bit mode, even though the architecture is 64 bit long.
  • nasm should be a recent version
  • gcc will be in 64-bit mode, and libgcc-devel.i386 should be installed to allow gcc to compile and link 32-bit object files

On Ubuntu

  • Login to Hadoop0
  • install libgcc-devel
    sudo apt-get install libc6-dev-i386
  • test sample program (prog1.asm) above:
    nasm -f elf prog1.asm
    nasm -f elf asm_io.asm
    gcc  -m32 driver.c  *.o
    ./a.out
It should work!

On Fedora

  • Haven't solved that yet...