Recently, Tari on Cemetech posted a short piece about programming Assembly for C libraries. In order to generate libraries usable in C programs, a specific format must be used. First of all, the registers are each assigned the following uses by GCC:
- r0-r1 Stores function return value, caller saves.
- r2-r3 Scratch space, caller saves.
- r4-r7 Function parameters, caller saves.
- r8-r13 Scratch, callee saves.
- r14 Frame pointer, callee saves.
- r15 Stack pointer, callee saves.
- MACH,MACL Callee saves.
If an argument is more than 32 bits long, it's pushed onto the stack rather than split amongst different registers.
The format for a function in such a library is to declare the function global with the .global tag. An example of this would be this function to return the jump to a syscall:
.global _Syscall
/* Syscall(short <syscall number>) */
/* Jumps to the syscall */
mov.l Table,r2
shll2 r4
mov.l @(r4+r2),r0
jsr @r0
nop
nop
Table: .long 0x805EDCA8
The code is then included in the compiled code with the #include <example.s> declaration.
Using this, I've been working on a few libraries recently to help with some of GCC's weak areas and other speed critical functions.
Partial list of implemented and planned functions for my math library (which I've actually had around for quite some time):
Modulus
Arbitrary precision addition
Arbitrary precision subtraction
Arbitrary precision multiplication
Arbitrary precision integer division
Hardware division
64 bit operations
Single precision Floating point operations
OS variable floating point operations
Integer Square root
Integer inverse square root
Floating point -> integer conversion
Integer->Floating point conversion
Floating point Absolute value (it's like two lines, but whatever :p)