mirror of
https://github.com/pkivolowitz/asm_book.git
synced 2026-06-23 07:28:04 +08:00
corrected text to conform to corrected code in nine_args
This commit is contained in:
parent
c5143f19db
commit
73bad628b4
2 changed files with 66 additions and 47 deletions
|
|
@ -271,62 +271,76 @@ This example hurts my brain: 8 9
|
||||||
In assembly language, this program could be written as:
|
In assembly language, this program could be written as:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
.text // 1
|
.text // 1
|
||||||
.global main // 2
|
.global main // 2
|
||||||
// 3
|
// 3
|
||||||
SillyFunction: // 4
|
/* Demonstration of using more than 8 arguments to a function. This // 4
|
||||||
str x30, [sp, -16]! // 5
|
demo is LINUX only as APPLE will put all arguments beyond the first // 5
|
||||||
ldr x0, =fmt // 6
|
one on the stack anyway. // 6
|
||||||
mov x1, x7 // 7
|
// 7
|
||||||
ldr x2, [sp, 16] // 8
|
On LINUX, all parameters to a function beyond the eight go on the // 8
|
||||||
bl printf // 9
|
stack. The first 8 go in registers x0 through x7 as normal (for // 9
|
||||||
ldr x30, [sp], 32 // 10
|
LINUX). // 10
|
||||||
ret // 11
|
*/ // 11
|
||||||
// 12
|
// 12
|
||||||
main: // 13
|
SillyFunction: // 13
|
||||||
str x30, [sp, -16]! // 14
|
stp x29, x30, [sp, -16]! // Changes sp. // 14
|
||||||
mov x0, 9 // 15
|
mov x29, sp // 15
|
||||||
str x0, [sp, -16]! // 16
|
ldr x0, =fmt // 16
|
||||||
mov x0, 1 // 17
|
mov x1, x7 // 17
|
||||||
mov x1, 2 // 18
|
ldr x2, [sp, 16] // This does not alter the sp. // 18
|
||||||
mov x2, 3 // 19
|
bl printf // 19
|
||||||
mov x3, 4 // 20
|
ldp x29, x30, [sp], 16 // Undoes change to sp. // 20
|
||||||
mov x4, 5 // 21
|
ret // 21
|
||||||
mov x5, 6 // 22
|
// 22
|
||||||
mov x6, 7 // 23
|
main: // 23
|
||||||
mov x7, 8 // 24
|
stp x29, x30, [sp, -16]! // sp down total of 16. // 24
|
||||||
bl SillyFunction // 25
|
mov x29, sp // 25
|
||||||
ldr x30, [sp], 32 // 26
|
mov x0, 9 // 26
|
||||||
ret // 27
|
str x0, [sp, -16]! // sp down total of 32. // 27
|
||||||
// 28
|
mov x0, 1 // 28
|
||||||
.data // 29
|
mov x1, 2 // 29
|
||||||
fmt: .asciz "This example hurts: %ld %ld\n" // 30
|
mov x2, 3 // 30
|
||||||
// 31
|
mov x3, 4 // 31
|
||||||
|
mov x4, 5 // 32
|
||||||
|
mov x5, 6 // 33
|
||||||
|
mov x6, 7 // 34
|
||||||
|
mov x7, 8 // 35
|
||||||
|
bl SillyFunction // 36
|
||||||
|
add sp, sp, 16 // undoes change of sp by 16 due // 37
|
||||||
|
// to function call. // 38
|
||||||
|
ldp x29, x30, [sp], 16 // undoes change to sp of 16. // 39
|
||||||
|
ret // 40
|
||||||
|
// 41
|
||||||
|
.data // 42
|
||||||
|
fmt: .asciz "This example hurts my brain: %ld %ld\n" // 43
|
||||||
|
// 44
|
||||||
|
.end // 45
|
||||||
```
|
```
|
||||||
|
|
||||||
Notice how `main()` puts the first 8 parameters into the scratch
|
Notice how `main()` puts the first 8 parameters into the scratch
|
||||||
registers `x0` through `x7` using `Lines 17` to `24`. But first, it put
|
registers `x0` through `x7` using `Lines 28` to `35`. But first, it put
|
||||||
the ninth parameter onto the stack. It did the stack parameter first so
|
the ninth parameter onto the stack. It did the stack parameter first so
|
||||||
that the stack pointer could be manipulated in a scratch register.
|
that the stack pointer could be manipulated in a scratch register since
|
||||||
|
all the scratch registers are being used for parameters.
|
||||||
|
|
||||||
After executing `Line 14`, the stack will have:
|
After executing `Line 24`, the stack will have:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
sp + 0 return address for main
|
sp + 0 return address for main
|
||||||
sp + 8 zero
|
sp + 8 former contents of frame pointer
|
||||||
```
|
```
|
||||||
|
|
||||||
After executing `Line 16`, the stack will have:
|
After executing `Line 27`, the stack will have:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
sp + 0 9
|
sp + 0 9
|
||||||
sp + 8 garbage
|
sp + 8 garbage
|
||||||
sp + 16 return address for main
|
sp + 16 return address for main
|
||||||
sp + 24 zero
|
sp + 24 former contents of frame pointer
|
||||||
```
|
```
|
||||||
|
|
||||||
After executing `Line 5`, the stack will have:
|
After executing `Line 14`, the stack will have:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
sp + 0 return address for SillyFunction
|
sp + 0 return address for SillyFunction
|
||||||
|
|
@ -334,31 +348,36 @@ sp + 8 garbage
|
||||||
sp + 16 9
|
sp + 16 9
|
||||||
sp + 24 garbage
|
sp + 24 garbage
|
||||||
sp + 32 return address for main
|
sp + 32 return address for main
|
||||||
sp + 40 zero
|
sp + 40 former contents of frame pointer
|
||||||
```
|
```
|
||||||
|
|
||||||
This means that `Line 8` fetches `p9` from memory and puts its value
|
This means that `Line 18` fetches `p9` from memory and puts its value
|
||||||
into x2 (where it becomes the third argument to `printf()`).
|
into x2 (where it becomes the third argument to `printf()`).
|
||||||
|
|
||||||
## A bit of history
|
## A bit of history
|
||||||
|
|
||||||
The early Unix kernels would abuse the calling convention to
|
The early Unix kernels would abuse the calling convention to
|
||||||
miraculously pass return values back to calling functions. Early
|
miraculously pass return values back to calling functions.
|
||||||
versions of C made extensive use of a now obsolete keyword `register`.
|
|
||||||
It was an instruction to the compiler to store a certain variable in
|
|
||||||
a register and not in memory in the code the compiler produced.
|
|
||||||
|
|
||||||
Particularly abusive functions would call other functions without
|
Particularly abusive functions would call other functions without
|
||||||
passing any actual variables but the parameters would indeed be passed!
|
passing any actual variables but the parameters would indeed be passed!
|
||||||
|
|
||||||
The coders assumed the compiler would store specific variables in
|
The coders assumed the compiler would store specific variables in
|
||||||
specific registers, avoiding the overhead of using the actual calling
|
specific registers, avoiding the overhead of using the actual calling
|
||||||
convention they themselves defined. Code that did this had to be
|
convention they themselves defined. Code that did this had to be
|
||||||
rewritten once Unix began to be ported to machines beyond the original
|
rewritten once Unix began to be ported to machines beyond the original
|
||||||
DEC hardware.
|
DEC* hardware.
|
||||||
|
|
||||||
This had the author scratching his head until he figured it out, way
|
This had the author scratching his head until he figured it out, way
|
||||||
way back in the day.
|
way back in the day.
|
||||||
|
|
||||||
|
(Early versions of C made extensive use of a now obsolete keyword
|
||||||
|
`register`. It was an instruction to the compiler to store a certain
|
||||||
|
variable in a register and not in memory in the code the compiler
|
||||||
|
produced.)
|
||||||
|
|
||||||
|
*Trivia: DEC shouldn't be used in place of Digital Equipment Corporation
|
||||||
|
after the Dairy Equipment Company asserted its right to "DEC".
|
||||||
|
|
||||||
Those were the days when the entire Unix kernel would be printed out to
|
Those were the days when the entire Unix kernel would be printed out to
|
||||||
form a stack of paper less than an inch high. The author knows this
|
form a stack of paper less than an inch high. The author knows this
|
||||||
because [Jishnu
|
because [Jishnu
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in a new issue