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
|
|
|
|
|
2019-09-08 19:04:07 +02:00
|
|
|
Stack grows downward. 'ebp' and 'esp' are both used.
|
|
|
|
The lowest stack frame is marked by having 'ebp' = 0.
|
|
|
|
There is a 128-bytes red zone below 'esp'.
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
A function's assembly code looks like this:
|
|
|
|
label:
|
2019-08-21 16:57:32 +02:00
|
|
|
enter N*8
|
2019-06-15 20:21:38 +02:00
|
|
|
...
|
|
|
|
...
|
|
|
|
...
|
|
|
|
leave
|
|
|
|
ret
|
2019-06-16 12:48:30 +02:00
|
|
|
'N' is the number of local variables used by the function.
|
2019-08-21 16:57:32 +02:00
|
|
|
'N' may be omitted if it is zero.
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-07-15 20:58:17 +02:00
|
|
|
The above code is equivalent to (and can be substitued by) the following:
|
2019-06-15 20:21:38 +02:00
|
|
|
label:
|
2019-09-08 19:04:07 +02:00
|
|
|
push ebp
|
|
|
|
mov ebp, esp
|
|
|
|
sub esp, N*8
|
2019-06-15 20:21:38 +02:00
|
|
|
...
|
|
|
|
...
|
|
|
|
...
|
2019-09-08 19:04:07 +02:00
|
|
|
mov esp, ebp
|
|
|
|
pop ebp
|
2019-06-15 20:21:38 +02:00
|
|
|
ret
|
|
|
|
|
|
|
|
Between the 'enter' and the 'leave', the stack looks like this:
|
|
|
|
. .
|
|
|
|
. .
|
|
|
|
. (caller's) .
|
|
|
|
|---------------|
|
2019-09-08 19:04:07 +02:00
|
|
|
| saved eip | ebp+8 esp+(N*8)+16
|
|
|
|
| saved ebp | ebp esp+(N*8)+8
|
|
|
|
| . | ebp-8 esp+(N*8) \
|
|
|
|
| . | ebp-16 esp+(N-1)*8 |
|
2019-07-15 20:58:17 +02:00
|
|
|
| . | ... | <- local
|
2019-09-08 19:04:07 +02:00
|
|
|
| . | ebp-(N-1)*8 esp+8 | variables
|
|
|
|
| . | ebp-(N*8) esp |
|
2019-07-15 20:58:17 +02:00
|
|
|
|---------------| /
|
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)
|
2019-09-08 19:04:07 +02:00
|
|
|
- never uses any function that changes 'ebp' nor 'esp',
|
2019-06-15 20:21:38 +02:00
|
|
|
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:
|
2019-09-08 19:04:07 +02:00
|
|
|
- 'ebp' must be 8-bytes aligned
|
|
|
|
- 'esp' must be 8-bytes aligned
|
2019-06-15 20:21:38 +02:00
|
|
|
- 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-22 13:18:13 +02:00
|
|
|
ax0, ax1, ax2, ax3, ax4, ax5
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-07-22 13:18:13 +02:00
|
|
|
Further parameters are passed on the stack in reverse order. The caller then
|
|
|
|
cleans the stack.
|
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-09-08 19:04:07 +02:00
|
|
|
eax, edx
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-07-22 13:18:13 +02:00
|
|
|
The following registers are volatile; the caller cannot assume
|
|
|
|
that they will be left unmodified by the callee:
|
2019-09-08 19:04:07 +02:00
|
|
|
eax, ebx, ecx, edx, esi, edi, ax0, ax1, ax2, ax3, ax4, ax5
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-07-22 13:18:13 +02:00
|
|
|
The following registers are nonvolatile; the callee must preserve them:
|
2019-09-08 19:04:07 +02:00
|
|
|
nx0, nx1, nx2, nx3, nx4, nx5, nx6, nx7, nx8
|
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:
|
2019-09-08 19:04:07 +02:00
|
|
|
sub esp, nargs * 8
|
|
|
|
mov [esp], arg0
|
2019-06-17 20:59:30 +02:00
|
|
|
...
|
|
|
|
...
|
|
|
|
...
|
2019-09-08 19:04:07 +02:00
|
|
|
mov [esp+(N*8)], argN
|
2019-06-17 20:59:30 +02:00
|
|
|
call variadic_func
|
2019-09-08 19:04:07 +02:00
|
|
|
add esp, nargs * 8
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
To the variadic function, argN can be accessed the following way:
|
2019-09-08 19:04:07 +02:00
|
|
|
mov reg, [ebp+N*8+16]
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
For instance:
|
2019-09-08 19:04:07 +02:00
|
|
|
mov eax, [ebp+16] ; arg0
|
|
|
|
mov edx, [ebp+24] ; arg1
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
It is recommended to use the reg+reg*imm16+imm16 memory format:
|
2019-09-08 19:04:07 +02:00
|
|
|
mov eax, [ebp+ecx*8+16] ; accesses arg#ecx
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
The 'va_list' type can be regarded as a pointer to the
|
2019-09-08 19:04:07 +02:00
|
|
|
variadic function's ebp+16
|
2019-06-17 20:59:30 +02:00
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|
|
|
|
4. SPECIAL REGISTERS
|
2019-06-15 20:21:38 +02:00
|
|
|
|
2019-07-15 20:47:44 +02:00
|
|
|
(TO BE COMPLETED)
|
2019-06-15 20:21:38 +02:00
|
|
|
|
|
|
|
#------------------------------------------------------------------------------#
|
|
|
|
|