Assembly Language Lab

CS63: Principles of Computer Organization
Fall Semester, 1997

Ray Ontko
Department of Computer Science
Earlham College

The purpose of this lab is to give you a chance to examine and modify assembly language programs.

Imagine that you are working on a program with a time-critical portion which you would like to improve. Your program (written in C) is using a "trial division" approach to factoring primes, and at one point you calculate both the quotient (/) and remainder (%). You recall (from your computer organization course in college) that the 80386 has an instruction which computes both simultaneously during division and wanted to find out if the compiler is using this optimal approach, and if not, fix it.

So, you wrote a small test program to see how the compiler handles the situation:

#include <stdio.h>
#include <stdlib.h>

void main()
{
int i ;
int a ;
int b ;
int q ;
int r ; 

a = 23 ;
b = 5 ;

for ( i = 0 ; i < 1000000 ; i ++ )
  { 
  q = a / b ;
  r = a % b ;
  }

printf( "a %d  b %d  q %d  r %d\n", a , b , q , r ) ;

exit( EXIT_SUCCESS ) ;
}
Using this program, do the following:
  1. Connect to a system which has the Gnu C compiler (gcc) and the Gnu assembler (as) and runs on an Intel 386 processor. Copy the program listed above to a file called test.c.

  2. Use the following command to compile the program:
    cc test.c -o test
    

  3. Execute the program using "time" to display timing statistics:
    time ./test
    
    Make note of the different execution statistics given.

  4. Now, use the -S option of the Gnu compiler to stop the compilation and save the assembly listing. Type the command:
    cc -S test.c
    
    This produces a file "test.s" which contains the assembly language equivalent of your original program.

  5. Examine the assembly language listing. Can you explain the meaning of each line in terms of the original program?

  6. Verify that you can compile and execute the assembly language listing:
    rm test
    cc test.s -o test
    time ./test
    
    Here we delete the originally compiled version of the C program, assemble and link "test.s" to the file "test", and finally re-run the program. Again, note the timing statistics. How do they compare to the initial run?

  7. Using your favorite unix editor (vi or ae) modify the assembly language file to eliminate any redundant code that you think might affect the performance of the program.

  8. Reassemble and test your new program. Does it work correctly? How do the execution statistics compare?
    rm test
    cc test.s -o test
    time ./test
    
    Show your program and explain your results to the person next to you.

  9. Just for grins, copy test.c to tsetse.cs.earlham.edu or one of the other DecStations. Again, compile and test the program and note the execution times:
    cc test.c -o test
    time ./test
    
    Is the program faster or slower on the DecStation?

  10. Now, take a look at the assembly language:
    cc -S test.c
    
    How does the resulting "test.s" compare with that produced on the Intel machine? Are you able to explain the new assembly listing line by line? Do you notice any obvious improvements to the div/rem logic?

When you have completed the lab, turn in your timing statistics and a brief writeup of what changes you made to the assembly listing on the Intel 386.

Copyright © 1997, Ray Ontko (rayo@ontko.com).
If you're curious about why I copyright, see Peter Suber's Why Copyright Web Documents?.