2019-06-15 20:21:38 +02:00
|
|
|
# The OS/K Team licenses this file to you under the MIT license.
|
|
|
|
# See the LICENSE file in the project root for more information.
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
1. STACK
|
|
|
|
|
|
|
|
Stack grows downward. 'rbp' and 'rsp' are both used.
|
2019-06-20 12:31:36 +02:00
|
|
|
The lowest stack frame is marked by having 'rbp' = 0.
|
|
|
|
There is a 128-bytes red zone below 'rsp'.
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
A function's assembly code looks like this:
|
|
|
|
label:
|
|
|
|
enter N
|
|
|
|
...
|
|
|
|
...
|
|
|
|
...
|
|
|
|
leave
|
|
|
|
ret
|
2019-06-16 12:48:30 +02:00
|
|
|
'N' is the number of local variables used by the function.
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-06-16 11:58:12 +02:00
|
|
|
The above code is equivalent to the following, but much faster:
|
2019-06-15 20:21:38 +02:00
|
|
|
label:
|
|
|
|
mov [rsp-8], rbp
|
|
|
|
lea rbp, [rsp-8]
|
|
|
|
sub rsp, (N+1)*8
|
|
|
|
...
|
|
|
|
...
|
|
|
|
...
|
2019-06-16 11:58:12 +02:00
|
|
|
lea rsp, [rbp+8]
|
|
|
|
mov rbp, [rbp]
|
2019-06-15 20:21:38 +02:00
|
|
|
ret
|
|
|
|
|
|
|
|
Between the 'enter' and the 'leave', the stack looks like this:
|
|
|
|
. .
|
|
|
|
. .
|
|
|
|
. (caller's) .
|
|
|
|
|---------------|
|
|
|
|
| saved rip | rbp+8
|
|
|
|
| saved rbp | rbp+0
|
|
|
|
| . | rsp+(N*8) \
|
|
|
|
| . | ... |
|
|
|
|
| . | ... |
|
|
|
|
| . | ... |- Local variables
|
|
|
|
| . | rsp+16 |
|
|
|
|
| . | rsp+8 |
|
|
|
|
| . | rsp+0 /
|
|
|
|
|---------------|
|
2019-07-01 21:46:36 +02:00
|
|
|
. (red zone) .
|
2019-06-15 20:21:38 +02:00
|
|
|
. .
|
|
|
|
. .
|
|
|
|
|
|
|
|
|
|
|
|
'enter' and 'leave' can be omitted if ALL the following hold:
|
|
|
|
the function
|
|
|
|
- uses no local variables (on the stack)
|
|
|
|
- never uses any function that changes 'rbp' nor 'rsp',
|
|
|
|
aside from 'call' and 'ret'
|
|
|
|
|
2019-06-16 14:01:58 +02:00
|
|
|
You can never omit 'enter' without omitting 'leave', and vice-versa.
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
2. CALLING CONVENTION
|
|
|
|
|
|
|
|
No matter whether 'enter' and 'leave' were ommited or not, the following must
|
|
|
|
hold true whenever a function is entered or exited from:
|
|
|
|
- 'rbp' must be 8-bytes aligned
|
|
|
|
- 'rsp' must be 8-bytes aligned
|
|
|
|
- the DF flag must be cleared
|
|
|
|
|
|
|
|
Aside from the DF flag, a function cannot assume anything about the state
|
|
|
|
of the flags in the FLG register.
|
|
|
|
|
|
|
|
Passing parameters is done using the following registers, in that order:
|
2019-07-01 00:45:08 +02:00
|
|
|
ax0-ax9, a10-a31
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
The stack is never used for argument passing, except for variadic functions,
|
|
|
|
cf the next section. If you need to pass large structures of data, pass
|
|
|
|
their address in an appropriate register.
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
Return values are passed in 'rax'. If the return value does not fit
|
|
|
|
and require more registers, use the following registers, in that order:
|
2019-07-01 00:52:37 +02:00
|
|
|
rax, rdx, a16-a31
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
The following registers are volatile; the calling function cannot assume
|
|
|
|
that they will be left unmodified by the called function:
|
2019-07-01 00:45:08 +02:00
|
|
|
rax, rcx, rdx, rx8-r31, ax0-a31
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
The following registers are nonvolatile; the called function must preserve them:
|
2019-07-01 00:45:08 +02:00
|
|
|
rbx, rsi, rdi, nx0-n31, rbp, rsp
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
2019-06-17 20:59:30 +02:00
|
|
|
3. VARIADIC FUNCTIONS
|
|
|
|
|
|
|
|
To call a variadic function, do this:
|
|
|
|
sub rsp, nargs * 8
|
|
|
|
mov [rsp], arg0
|
|
|
|
...
|
|
|
|
...
|
|
|
|
...
|
|
|
|
mov [rsp+(N*8)], argN
|
|
|
|
call variadic_func
|
|
|
|
add rsp, nargs * 8
|
|
|
|
|
|
|
|
To the variadic function, argN can be accessed the following way:
|
2019-06-21 22:19:55 +02:00
|
|
|
mov reg, [rbp+N*8+16]
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
For instance:
|
2019-06-21 22:19:55 +02:00
|
|
|
mov rax, [rbp+16] ; arg0
|
|
|
|
mov rdx, [rbp+24] ; arg1
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
It is recommended to use the reg+reg*imm16+imm16 memory format:
|
2019-06-21 22:19:55 +02:00
|
|
|
mov rax, [rbp+rcx*8+16] ; accesses arg#rcx
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
The 'va_list' type can be regarded as a pointer to the
|
|
|
|
variadic function's rbp+16
|
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
4. SPECIAL REGISTERS
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
The 'inv' register cannot be referenced by machine code except when specified
|
|
|
|
as an offset register in the [reg+reg(*/+...)] memory formats; in these case,
|
|
|
|
'inv' can be assumed to be always null.
|
|
|
|
|
2019-07-01 00:45:08 +02:00
|
|
|
The following registers can only be used by the supervisor:
|
|
|
|
- Fast global variables for the supervisor:
|
2019-06-15 20:21:38 +02:00
|
|
|
sa0-sa7
|
2019-07-01 00:45:08 +02:00
|
|
|
- Debugging registers for the supervisor:
|
|
|
|
dr0-dr7
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-07-01 21:46:36 +02:00
|
|
|
The following registers cannot be referenced by machine code at all:
|
2019-07-01 00:45:08 +02:00
|
|
|
px0-px1, fc0-fc2, cr0-cr7
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|