The following is a small C program, trivial.c (which is very similar to a mini-Oberon program), and the resulting output from the cc compiler (/opt/SUNWspro/bin/cc to be exact) with the command cc -S trivial.c (I've added the long comments). Not all of this will make sense immediately, but it should give you a good idea of what to aim for.
main () { int a, b, c; a = 99; b = a + two(); if (b > 100) printf ("%d\n", b); } two () { return 2; } -------------------------------------------------------------------- ! Header stuff first. Declare that we are writing code: "text" ! The next few lines are needed for each function that is declared. ! These are directions to the assembler. They are not real instructions; ! they're declarations. All "dot" commands are declarations of some kind. .section ".text",#alloc,#execinstr .align 8 .skip 16 ! block 0 ! This makes main a label that is visible outside this file. ! I don't know what the second command does. Finally, we get ! the actual goto label for main. "call main" will result in ! a jump to this spot in the code, plus some other things. .global main .type main,2 main: ! The next line sets up storage for main's local variables ! (rather cryptically, I might add). The important value to look at ! is -112, which is set to the actual number of bytes of space that ! main's activation record requires. How this number is calculated ! will be discussed later. One thing worth knowing now is that the ! code generator doesn't actually know this value when it is at this ! part of the program. So we'll use a name here and give the name a ! value at the *bottom* of the file. save %sp,-112,%sp ! block 1 .L14: ! File ex.c: ! 1 int main () ! 2 { ! 3 int a, b, c; ! 4 a = 99; ! The next two lines perform an assignment of the value 99 ! to the variable 'a'. 'a' is the main's first local variable -- all ! local variables are referenced using the frame pointer (%fp) -- in ! this case, the address of 'a' is found by subtracting 8 from fp. | For most assembly languages, one move instruction would suffice for ! a simple assignment like this -- however, the Sparc does not allow ! a constant to be assigned to a stack location with a 'mov', so ! we first store ('st') the constant in a local register (%l0), and ! then move the register value to the stack location. mov 99,%l0 ! note: everything done out of registers st %l0,[%fp-8] ! store 99 in a's location ! 5 b = a + two(); ! We now want to perform the add. This requires that we reload a into ! a register and call two() and retrieve its return value. ! The 'nop' is needed after every function call due to the Sparc's ! tendency to pipeline (pre-fetch) instructions (we'll partially ! explain this in class -- don't worry about now -- just get in the ! habit of always outputing a 'nop' after a 'call'). BTW, the way we ! will handle registers may do all the register loading *after* all the ! functions are called, etc. in the expression. ld [%fp-8],%l0 ! load a back into a register call two nop ! By convention, the return value of a function will be in register ! %o0. The next three instructions, therefore, perform the add of 'a' ! and the result of 'two', storing the result in register %l0. ! (Personally, I would used %l2 for the result rather than reuse %l0.) ! Finally, take the result of the addition, and store in 'b'. 'b' is main's ! second local variable, so it's address is 4 more bytes from the frame ! pointer than 'a', 12 bytes total. mov %o0,%l1 ! retrieve result from output register add %l0,%l1,%l0 ! do the add st %l0,[%fp-12] ! store result in b ! 6 if (b > 100) ! Now we want to compare 'b' with 100. We move 'b' to ! register %l0, compare, and branch on *false*. Note the nop again -- ! we'll need one after every branch as well as function call. ld [%fp-12],%l0 ! load b cmp %l0,100 ! compare and ble .L16 ! branch on *inverted* condition nop ! block 2 .L17: ! 7 printf ("%d\n", b); ! If we make it here, we want to print. The compiler makes a ! normal function call to the C printf library routine, passing ! it two parameters -- the format string, and the variable. Below ! then, is declared the print string as a constant -- the "address" ! of this constant (.L19) will be the parameter to printf. I would ! prefer to just dump the string here rather than save it for the end, ! but it doesn't really matter: recall that the data is and text are ! stored in two completely different memory segments. sethi %hi(.L19),%l0 ! get fancy to load large number/addr or %l0,%lo(.L19),%l0 ! which is pointer to format string ld [%fp-12],%l1 ! load b mov %l0,%o0 ! move into argument-passing regs mov %l1,%o1 call printf ! call nop ! We're done with this function (.L16 is the "else" part of the ! if statement we handled above, and .LE13 is apparently the "end- ! of-function" label. All we need to do is return. This is done ! with a jump off the value of the input register %i7, the saved PC. ! Adding skips over the original call instruction and the nop after it. ! The 'restore' instruction does some cleanup -- the reason it comes after ! the return ('jmp') is again due to Sparc pipelining. Rather than ! doing a jump, you can also use the "ret" macro, which does exactly ! the same thing. The last two commands are just cleanup stuff for the ! assembler. ! block 3 .L16: .L13: jmp %i7+8 ! this is a ref to the return PC restore ! in delay slot, execs with jmp .size main,(.-main) .align 8 ! Set up sequence happens all over again. Note similarities and differences. .align 8 .skip 16 ! block 0 .global two .type two,2 two: save %sp,-104,%sp ! smaller value here because no locals. ! block 1 .L22: ! File ex.c: ! 8 } ! 9 ! 10 int two () ! 11 { ! 12 return 2; mov 2,%l0 st %l0,[%fp-4] ba .L21 nop ! block 2 .L21: ld [%fp-4],%l0 mov %l0,%i0 jmp %i7+8 restore .size two,(.-two) .align 8 ! The compiler saved this constant until the end, but it can be put anywhere ! as long as it is declared to be in the data segment and then the text ! segment is redeclared to continue generating code. .section ".data1",#alloc,#write .align 4 .L19: .ascii "%d\n\000" .type .L19,#object .size .L19,4 ! Random footer stuff that you probably don't need. .file "trivial.c" .xstabs ".stab.index","Xa ; V=3.1 ; R=WorkShop Compilers 4.2 01 Oct 1997 C 4.2 patch 104668-05",60,0,0,0 .xstabs ".stab.index","/net/cs/htdocs/users/wgg/CSE131B/Project; /opt/SUNWspro/bin/../SC4.2/bin/cc -S trivial.c -W0,-xp",52,0,0,0 .xstabs ".stab.index","main",42,0,0,0 .ident "acomp: WorkShop Compilers 4.2 01 Oct 1997 C 4.2 patch 104668-05" ! This is how the compiler declares constants. It can declare them at the ! and still use them anywhere in the file. .global __fsr_init_value __fsr_init_value = 0x0