mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 19:29:37 +00:00
211 lines
7.4 KiB
Plaintext
211 lines
7.4 KiB
Plaintext
<!doctype linuxdoc system>
|
|
|
|
<article>
|
|
<title>cc65 internals
|
|
<author><url url="mailto:bbbradsmith@users.noreply.github.com" name="Brad Smith">
|
|
|
|
<abstract>
|
|
Internal details of cc65 code generation,
|
|
such as the expected linker configuration,
|
|
and calling assembly functions from C.
|
|
</abstract>
|
|
|
|
<!-- Table of contents -->
|
|
<toc>
|
|
|
|
<!-- Begin the document -->
|
|
|
|
|
|
|
|
<sect>Linker configuration<p>
|
|
|
|
The C libraries and code generation depend directly on a suitable linker configuration.
|
|
There are premade configuration files in the <tt/cfg// directory, normally chosen by the
|
|
linker's selected target. These can be used as a template for customization.
|
|
|
|
The C libraries depend on several special segments to be defined in your linker configuration.
|
|
Generated code will also use some of them by default.
|
|
Some platform libraries have additional special segments.
|
|
|
|
Memory areas are free to be defined in a way that is appropriate to each platform,
|
|
and the segments they contain are used as a layer of semantics and abstraction,
|
|
to allow much of the reorganization to be done with the linker config,
|
|
rather than requiring platform-specific code source changes.
|
|
|
|
<sect1><tt/ZEROPAGE/ segment<p>
|
|
|
|
Used by the C library and generated code for efficient internal and temporary state storage,
|
|
also called "pseudo-registers".
|
|
|
|
<sect1><tt/STARTUP/ segment<p>
|
|
|
|
Used by each platform instance of the C library in <tt/crt0.s/ to contain the entry point
|
|
of the program.
|
|
|
|
The startup module will export <tt/__STARTUP__ : absolute = 1/ to force the linker to
|
|
always include <tt/crt0.s/ from the library.
|
|
|
|
<sect1><tt/CODE/ segment<p>
|
|
|
|
The default segment for generated code, and most C library code will be located here.
|
|
|
|
Use <tt/#pragma code-name/ to redirect generated code to another segment.
|
|
|
|
<sect1><tt/BSS/ segment<p>
|
|
|
|
Used for uninitialized variables.
|
|
Originally an acronym for "Block Started by Symbol", but the meaning of this is now obscure.
|
|
|
|
Use <tt/#pragma bss-name/ to redirect uninitialized variables to another segment.
|
|
|
|
<sect1><tt/DATA/ segment<p>
|
|
|
|
Used for initialized variables.
|
|
|
|
On some platforms, this may be initialized as part of the program loading process,
|
|
but on others it may have a separate <tt/LOAD/ and <tt/RUN/ address,
|
|
allowing <tt/copydata/ to copy the initialization from the loaded location
|
|
into their run destination in RAM.
|
|
|
|
Use <tt/#pragma data-name/ to redirect initialized variables to another segment.
|
|
|
|
<sect1><tt/RODATA/ segment<p>
|
|
|
|
Used for read-only (constant) data.
|
|
|
|
Use <tt/#pragma rodata-name/ to redirect constant data to another segment.
|
|
|
|
<sect1><tt/FEATURES/ table<p>
|
|
|
|
This currently defines table locations for the <tt/CONDES/
|
|
constructor, destructor, and interruptor features.
|
|
Some platform libraries use these.
|
|
|
|
The constructors will be called with <tt/initlib/ at startup,
|
|
and the destructors with <tt/donelib/ at program exit.
|
|
Interruptors are called with <tt/callirq/.
|
|
|
|
|
|
|
|
<sect>Calling assembly functions from C<p>
|
|
|
|
<sect1>Calling conventions<p>
|
|
|
|
There are two calling conventions used in cc65:
|
|
|
|
<itemize>
|
|
<item><tt/cdecl/ - passes all parameters on the C-stack.
|
|
<p>
|
|
<item><tt/fastcall/ - passes the rightmost parameter in
|
|
registers <tt>A/X/sreg</tt> and all others on the C-stack.
|
|
<p>
|
|
</itemize>
|
|
|
|
The default convention is <tt/fastcall/, but this can be changed with
|
|
the <tt/--all-cdecl/ command line option. If a convention is specified in
|
|
the function's declaration, that convention will be used instead.
|
|
Variadic functions will always use <tt/cdecl/ convention.
|
|
|
|
If the <tt/--standard/ command line option is used,
|
|
the <tt/cdecl/ and <tt/fastcall/ keywords will not be available.
|
|
The standard compliant variations <tt/__cdecl__/ and <tt/__fastcall__/ are always available.
|
|
|
|
If a function has a prototype, parameters are pushed to the C-stack as their respective types
|
|
(i.e. a <tt/char/ parameter will push 1 byte), but if a function has no prototype, default
|
|
promotions will apply. This means that with no prototype, <tt/char/ will be promoted
|
|
to <tt/int/ and be pushed as 2 bytes. "K & R"-style forward declarations may be used,
|
|
but they will function the same as if no prototype was used.
|
|
|
|
<sect1>Prologue, before the function call<p>
|
|
|
|
If the function is declared as fastcall, the rightmost argument will be loaded into
|
|
the <tt>A/X/sreg</tt> registers:
|
|
|
|
<itemize>
|
|
<item><tt/A/ - 8-bit parameter, or low byte of larger types<p>
|
|
<item><tt/X/ - 16-bit high byte, or second byte of 32-bits<p>
|
|
<item><tt/sreg/ - Zeropage pseudo-register including high 2 bytes of 32-bit parameter<p>
|
|
</itemize>
|
|
|
|
All other parameters will be pushed to the C-stack from left to right.
|
|
The rightmost parameter will have the lowest address on the stack,
|
|
and multi-byte parameters will have their least significant byte at the lower address.
|
|
|
|
The <tt/sp/ pseudo-register is a zeropage pointer to the base of the C-stack.
|
|
If the function is variadic, the <tt/Y/ register will contain the number of
|
|
bytes pushed to the stack for this function.
|
|
|
|
Example:
|
|
<tscreen><verb>
|
|
// C prototype
|
|
void cdecl foo(unsigned bar, unsigned char baz);
|
|
|
|
; C-stack layout within the function:
|
|
;
|
|
; +------------------+
|
|
; | High byte of bar |
|
|
; Offset 2 ->+------------------+
|
|
; | Low byte of bar |
|
|
; Offset 1 ->+------------------+
|
|
; | baz |
|
|
; Offset 0 ->+------------------+
|
|
|
|
; Example code for accessing bar. The variable is in A/X after this code snippet:
|
|
;
|
|
ldy #2 ; Offset of high byte of bar
|
|
lda (sp),y ; High byte now in A
|
|
tax ; High byte now in X
|
|
dey ; Offset of low byte of bar
|
|
lda (sp),y ; Low byte now in A
|
|
</verb></tscreen>
|
|
|
|
<sect1>Epilogue, after the function call<p>
|
|
|
|
<sect2>Return requirements<p>
|
|
|
|
If the function has a return value, it will appear in the <tt>A/X/sreg</tt> registers.
|
|
|
|
Functions with an 8-bit return value (<tt/char/ or <tt/unsigned char/) are expected
|
|
to promote this value to a 16-bit integer on return, and store the high byte in <tt/X/.
|
|
The compiler will depend on the promoted value in some cases (e.g. implicit conversion to <tt/int/),
|
|
and failure to return the high byte in <tt/X/ will cause unexpected errors.
|
|
This problem does not apply to the <tt/sreg/ pseudo-register, which is only
|
|
used if the return type is 32-bit.
|
|
|
|
If the function has a void return type, the compiler will not depend on the result
|
|
of <tt>A/X/sreg</tt>, so these may be clobbered by the function.
|
|
|
|
The C-stack pointer <tt/sp/ must be restored by the function to its value before the
|
|
function call prologue. It may pop all of its parameters from the C-stack
|
|
(e.g. using the <tt/runtime/ function <tt/popa/),
|
|
or it could adjust <tt/sp/ directly.
|
|
If the function is variadic, the <tt/Y/ register contains the number of bytes
|
|
pushed to the stack on entry, which may be added to <tt/sp/ to restore its
|
|
original state.
|
|
|
|
The internal pseudo-register <tt/regbank/ must not be changed by the function.
|
|
|
|
<sect2>Clobbered state<p>
|
|
|
|
The <tt/Y/ register may be clobbered by the function.
|
|
The compiler will not depend on its state after a function call.
|
|
|
|
The <tt>A/X/sreg</tt> registers may be clobbered if any of them
|
|
are not used by the return value (see above).
|
|
|
|
Many of the internal pseudo-registers used by cc65 are available for
|
|
free use by any function called by C, and do not need to be preserved.
|
|
Note that if another C function is called from your assembly function,
|
|
it may clobber any of these itself:
|
|
|
|
<itemize>
|
|
<item><tt>tmp1 .. tmp4</tt><p>
|
|
<item><tt>ptr1 .. ptr4</tt><p>
|
|
<item><tt>regsave</tt><p>
|
|
<item><tt>sreg</tt> (if unused by return)<p>
|
|
</itemize>
|
|
|
|
|
|
|
|
</article>
|