mirror of
https://gitlab.os-k.eu/os-k-team/kvisc.git
synced 2023-08-25 14:05:46 +02:00
126 lines
3.8 KiB
Plaintext
126 lines
3.8 KiB
Plaintext
# 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.
|
|
The lowest stack frame is marked by having 'rbp' = 0.
|
|
There is a 128-bytes red zone below 'rsp'.
|
|
|
|
A function's assembly code looks like this:
|
|
label:
|
|
enter N*8
|
|
...
|
|
...
|
|
...
|
|
leave
|
|
ret
|
|
'N' is the number of local variables used by the function.
|
|
'N' may be omitted if it is zero.
|
|
|
|
The above code is equivalent to (and can be substitued by) the following:
|
|
label:
|
|
push rbp
|
|
mov rbp, rsp
|
|
sub rsp, N*8
|
|
...
|
|
...
|
|
...
|
|
mov rsp, rbp
|
|
pop rbp
|
|
ret
|
|
|
|
Between the 'enter' and the 'leave', the stack looks like this:
|
|
. .
|
|
. .
|
|
. (caller's) .
|
|
|---------------|
|
|
| saved rip | rbp+8 rsp+(N*8)+16
|
|
| saved rbp | rbp rsp+(N*8)+8
|
|
| . | rbp-8 rsp+(N*8) \
|
|
| . | rbp-16 rsp+(N-1)*8 |
|
|
| . | ... | <- local
|
|
| . | rbp-(N-1)*8 rsp+8 | variables
|
|
| . | rbp-(N*8) rsp |
|
|
|---------------| /
|
|
. (red zone) .
|
|
. .
|
|
. .
|
|
|
|
|
|
'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'
|
|
|
|
You can never omit 'enter' without omitting 'leave', and vice-versa.
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
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:
|
|
ax0, ax1, ax2, ax3, ax4, ax5
|
|
|
|
Further parameters are passed on the stack in reverse order. The caller then
|
|
cleans the stack.
|
|
|
|
Return values are passed in 'rax'. If the return value does not fit
|
|
and require more registers, use the following registers, in that order:
|
|
rax, rdx
|
|
|
|
The following registers are volatile; the caller cannot assume
|
|
that they will be left unmodified by the callee:
|
|
rax, rbx, rcx, rdx, rsi, rdi, ax0, ax1, ax2, ax3, ax4, ax5
|
|
|
|
The following registers are nonvolatile; the callee must preserve them:
|
|
r12, r13, r14, r15, r16, r17, r18, r19, r20
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
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:
|
|
mov reg, [rbp+N*8+16]
|
|
|
|
For instance:
|
|
mov rax, [rbp+16] ; arg0
|
|
mov rdx, [rbp+24] ; arg1
|
|
|
|
It is recommended to use the reg+reg*imm16+imm16 memory format:
|
|
mov rax, [rbp+rcx*8+16] ; accesses arg#rcx
|
|
|
|
The 'va_list' type can be regarded as a pointer to the
|
|
variadic function's rbp+16
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
4. SPECIAL REGISTERS
|
|
|
|
(TO BE COMPLETED)
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|