References:
Therefore, since the address can be up to 64 bits, we have to load it a piece at a time (part 2 of this series will show how to avoid this). @-signs within the assembler instruct the assembler to give a specially-processed form of a symbol value. The following are used here:
@highest
refers to bits 48-63 of a constant
@higher
refers to bits 32-47 of a constant
@h
refers to bits 16-31 of a constant
@l
refers to bits 0-15 of a constant
The instruction
ld
4, 0(7)
loads the value at the address in register 7 into register 4 (the zero means to add zero to that address). i.e. ld r4, 0(r7)
Each system call has an associated number. This number is stored in register zero before making the call. The rest of the arguments start in register three, and continue on for however many arguments the system call needs. Then the
sc
instruction causes the kernel to take over and respond to the request. The system call number for exit
is 1. Therefore, the first thing we need to do is to move the number 1 into register 0.
if the specified register is register 0, it doesn't add a register at all, and uses the number 0 instead. This seems confusing, but the reason for it is to allow PowerPCs to use the same instruction for adding as for loading (why?).
he exit system call takes one parameter -- the exit value. This is stored in register 3. Therefore, we need to move our answer from register 6 to register 3. The "register move" instruction rm
3, 6
performs the needed move. Now we are ready to tell the operating system we are ready for it to do its trick.The instruction to call the operating system is simply
sc
for "system call". This will invoke the operating system, which will read what we have in register 0 and register 3, and then exit with the contents of register 3 as our return value. On the command line, we can retrieve this value using the command echo $?
.
Just to point out, a lot of these instructions are redundant, but used for teaching purposes. For example, since first_value and second_value are essentially constant, there is no reason we can't just load them directly and skip the data section altogether. Likewise, we could have stored the results in register 3 to begin with (instead of register 6), and saved a register move. In fact, we could have used register 3 for both a source and a destination register. So, if we were just trying to be concise, we could have written it like this:
Listing 2. A short version of the first program
.section ".opd", "aw"
.align 3
.global _start
_start:
.quad ._start, .TOC.@tocbase, 0
.text
li 3, 1 #load "1" into register 3
li 4, 2 #load "2" into register 4
add 3, 3, 4 #add register 3 to register 4 and store the result in register 3
li 0, 1 #load "1" into register 0 for the system call
sc
No comments:
Post a Comment