Reputation: 21
I'm puzzled by the code from the Pintos OS, named loader.S. I don't get how the string .string "PiLo" is used by puts when there's no label involved.
sub %dx, %dx # Serial port 0.
mov $0xe3, %al # 9600 bps, N-8-1.
# AH is already 0 (Initialize Port).
int $0x14 # Destroys AX.
call puts
.string "PiLo"
puts:
xchg %si, %ss:(%esp)
push %ax
next_char:
mov %cs:(%si), %al
inc %si
test %al, %al
jz 1f
call putc
jmp next_char
1: pop %ax
xchg %si, %ss:(%esp)
ret
putc:
pusha
1: sub %bh, %bh # Page 0.
mov $0x0e, %ah # Teletype output service.
int $0x10
mov $0x01, %ah # Serial port output service.
sub %dx, %dx # Serial port 0.
2: int $0x14 # Destroys AH.
test $0x80, %ah # Output timed out?
jz 3f
movw $0x9090, 2b # Turn "int $0x14" above into NOPs.
3:
cmp $'\r', %al
jne popa_ret
mov $'\n', %al
jmp 1b
if someone can help to understand the code.
Upvotes: 2
Views: 59
Reputation: 26766
This is approach is called in-line parameter passing. I saw it first on now very old computers, for me the PDP-8.
The idea is that some kind of call instruction is followed by data. A call instruction captures the address of the data, intended as return address, but with inline parameter passing, the return address is first used as a pointer to that parameter data block. By agreement between caller and callee, the proper number of parameters are accessed while adjusting the return address past the parameter data block, so that eventual return returns to code of the caller past that parameter data block.
In that snippet of code, si
is used to hold the return address; si
is modified to consume the parameter string, and position the true return address after that string's null byte, in case there's more code to run upon returning to the caller. (In the case of this snippet, it would seem there is some missing code there.)
From here: https://people.computing.clemson.edu/~mark/subroutines/pdp8.html
Parameter passing
Parameters are typically passed in-line after thejms
instruction. The subroutine accesses the parameters via the stored return address, which it then increments so that it will point to the next instruction after the in-line parameters. A variable-length parameter list should start with a parameter count as the first in-line parameter.
Calling program structure
...
jms subr ! call with fixed number of parameters (two)
parm1, 1 ! first in-line parameter
parm2, 2 ! second in-line parameter
... ! subroutine will return here, after parms.
This style of parameter passing is rather efficient, and doesn't necessarily require a stack or stack pointer, as these older machines didn't have those! However, this form works well to pass read-only data, though it doesn't really support recursion or reentrance (with mutable formal parameters). Further, on some processors conflating code & data together like that can be problematic for performance, such as messing with the branch target mechanisms of the processor.
The search term in-line parameter passing is easily confused with more modern usage of another very similar term, which is inline function calling (an optimization that replaces a function call with a copy of the body of the called function, which removes function call overhead at the potential cost of space, however, also tends to enable further call-site specific optimization).
Upvotes: 2