Assembler: Learning to Read
- Convert C programs into assembly
objdumpto examine the assembly underlying a C function/program (Note:
objdumpis a GNU tool, so you need to use
clangto compile files if you want to use
- Read simple assembly
- Become comfortable with the typeless nature of assembly
Pull today's exercise code from the
cs61-exercises repository. We strongly encourage you to use the appliance today -- if you use your laptop, you are likely to get assembly code that looks quite different from what we expect and the observations we ask you to make and questions we ask you may be difficult to answer.
Varieties of functions that do nothing
In the asm-intro video, we introduced the function
func that took no parameters, did nothing, and returned nothing. That function is in the
1.c file in today's directory. Create a few variants of this function that take parameters and/or return a value and compare the assembly produced for the different variants (we recommend you name these variants 1a.c, 1b.c, etc (for consistency with some other examples we'll be doing). You can convert
c files to assembly without modifying the Makefile just by typing
make 1a.s. Alternatively you can add these to the
all target in the Makefile and just type
Include at least one variant that returns 0. Notice the assembly produced. Can you think of another way the compiler might have chosen to implement the return value? Why do you suppose the compiler chose the instruction it did? Build a
.o file and use objump to examine the code produced -- does that change your hypothesis.
The Sum Function
In the asm-operators video, we introduced the simple sum function, which you will find in the file
2.c. In addition, you will find three other files 2a.c, 2b.c, and 2c.c. Note that each of these differs slightly from 2.c in C, but produces identical assembly code. These examples highlight the difference between the C abstract machine, in which the programs are different, and the actual machine, where they are executed identically. Your task is to come up with as many other variants of the sum function that will produce the same assembly. Experiment with different parameter types and different ways of instructing the compiler to produce code that adds two numbers together. Spend at least five minutes trying to come up with some variants, but no more than 10 minutes.
Next, examine 3.c, 4.c, 5.c, and the s files they produce. Subtraction (3.c) and Multiplication (4.c) are pretty predictable, but the assembly for 5.c has a couple of interesting features. Use google or any other resource to figure out the answer to two questions:
- What does cltd do?
- Why does idivl take only one operand?
Operands of Different Sizes
Now create versions of the functions in 2.c-5.c with a variety of different types of different sizes, e.g., char, unsigned char, short, unsigned short). Pay particular attention to the following issues:
- How are signed and unsigned values treated differently?
- How are operands of different sizes treated differently?
In the video on operators you saw that there are logical operators as well as arithmetic ones. Let's experiment with some other related operations.
Examine the program 6.c. What is it doing?
Now build and examine the file 6.s. There are two interesting things about it:
- Note that although the second parameter is unsigned, the assembly code moves only a single byte in %cl. Why?
- Note the
shllinstruction. What do you suppose it does?
Next take a look at 7.c -- can you predict what code it will generate? Build and examine 7.s to see if you were right. Why do you suppose I implemented
mul4 and not just
mul2? If you can't figure it out, write
mul2 and see what happens.
Next take a look at 8.c. Build and examine 8.s. Is it what you expect? Predict any difference you might see if you change the parameter to an int instead of an unsigned. Then test it.
What happened? (Use Google or any other resource easily available to explain any instructions you don't understand.)
Write a function that just divides its parameter by 4. What do you expect to see in the assembly? Check your answer.
Moving things around in Memory
Write a simple C function, swap.c, that takes two pointers to integers and swaps their contents. Then produce the assembler output for that function. Try reading the assembly output and see if you can figure out what it's doing. Use scrap paper or a whiteboard to draw what's happening.
Examine what happens if you change the parameters and return values to be pointers to differently sized things. What happens?
- You can read assembly for simple programs!
- You have probably figured out how/where parameters are passed to functions
- You know how assembly instructions express arithmetic and logical and shift operators
- You have discovered just how smart the compiler is some times!
Please complete this short survey.