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