[ARM] Reusable Binary Modules: Import+Export Library

Examples of how to export functions to a library (.L) then import them from another module. Easy import+export by name using load and store directives. Create it once then forget about it. Reuse it millions of times.

In version=0: ARM mode. Fast-call a1-a4+v1-v4. 8 parameters maximum. Modular functions, "position independant" with no global references except to functions that are imported in the same order. Any "static" data or literal tables (text and big numbers) must be incorporated inside of the functions and use PC-relative loads. Absolute memory addresses are allowed (example: RAM, VGA, timer, devices).

[b]See ZIP Attachment 4 Updated Magic-ARM Library, Examples, Tests, Disassembler. Scroll down[/b]

[b]EXAMPLE LIBRARY: STRING.ASM > STRING.*L[/b][code]; EXPORT FUNCTIONS TO STRING.L

include 'library.inc'

export strlen, strcpy, strcmp, strequ

; strlen(s) - get string length, # characters

function strlen, s
  alias s=a1, b=a2, c=v1
  . c=1, b=s
  .while c           ; until 0
    . (u8) c=*s++    ; read c
  .endw
  . s--, s-b         ; return current-start
endf

; strcpy(a, b) - standard copy with 0 after

function strcpy, a, b
  alias a=a1, b=a2, c=v1
  . c=1
  .while c
    . (u8) c=*b++    ; read
    . (u8) *a++=c    ; copy
  .endw
  . a--              ; return end
endf

; strcmp(a, b) - lexical comparison.
; return <0>

function strcmp, a, b
  alias a=a1, b=a2,\
   c=v1, d=v2
   . c=1, d=c
  .while c=d         ; while equal
    . (u8) c=*a++
    . (u8) d=*b++
    .if c=0          ; and both nonzero
      .break
    .end
    .if d=0
      .break
    .end
  .endw
  . a=c-d            ; return *a-*b
endf

; strequ(a, b) - equal? return 1/0

function strequ, a, b
  strcmp
  .if false
    return 1
  .end
endf 0[/code][b]TEST EXAMPLE.ASM > EXAMPLE.*BIN[/b][code]; EXAMPLE. IMPORT FUNCTIONS FROM STRING.L

include 'z.inc'

import string,\
 strlen, strcpy, strcmp, strequ

; example code...

nop
strcpy 1, 2
strcmp 1, 2[/code][b]DISASSEMBLY OF STRING+DRAW[/b]
Syntaxes generate highly optimized ARM assembler:[code]00000000 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000004 E3A04001 mov    v1, 1
00000008 E1A01000 mov    a2, a1
0000000C E3540000 cmp    v1, 0
00000010 0A000001 beq    1Ch
00000014 E4D04001 ldrb   v1, [a1], 1
00000018 EAFFFFFB b      0Ch
0000001C E2500001 subs   a1, a1, 1
00000020 E0500001 subs   a1, a1, a2
00000024 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000028 E92D5FF0 stmdb  sp!, {v1-ip,lr}
0000002C E3A04001 mov    v1, 1
00000030 E3540000 cmp    v1, 0
00000034 0A000002 beq    44h
00000038 E4D14001 ldrb   v1, [a2], 1
0000003C E4C04001 strb   v1, [a1], 1
00000040 EAFFFFFA b      30h
00000044 E2500001 subs   a1, a1, 1
00000048 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
0000004C E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000050 E3A04001 mov    v1, 1
00000054 E1A05004 mov    v2, v1
00000058 E1540005 cmp    v1, v2
0000005C 1A000008 bne    84h
00000060 E4D04001 ldrb   v1, [a1], 1
00000064 E4D15001 ldrb   v2, [a2], 1
00000068 E3540000 cmp    v1, 0
0000006C 1A000000 bne    74h
00000070 EA000003 b      84h
00000074 E3550000 cmp    v2, 0
00000078 1A000000 bne    80h
0000007C EA000000 b      84h
00000080 EAFFFFF4 b      58h
00000084 E0540005 subs   a1, v1, v2
00000088 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
0000008C E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000090 EBFFFFED bl     4Ch
00000094 E3500000 cmp    a1, 0
00000098 1A000001 bne    0A4h
0000009C E3A00001 mov    a1, 1
000000A0 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
000000A4 E3A00000 mov    a1, 0
000000A8 E8BD9FF0 ldmia  sp!, {v1-ip,pc}

; Disassembly of DRAW.L:

00000000 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000004 E3A02000 mov    a3, 0
00000008 E3822C05 orr    a3, a3, 500h
0000000C E0130291 muls   a4, a2, a3
00000010 E0933080 adds   a4, a4, a1, lsl 1
00000014 E3A01000 mov    a2, 0
00000018 E3811602 orr    a2, a2, 200000h
0000001C E0910003 adds   a1, a2, a4
00000020 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000024 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000028 E3A02000 mov    a3, 0
0000002C E3822602 orr    a3, a3, 200000h
00000030 E3A01000 mov    a2, 0
00000034 E3811A0B orr    a2, a2, 0B000h
00000038 E3811701 orr    a2, a2, 40000h
0000003C E3510000 cmp    a2, 0
00000040 0A000002 beq    50h
00000044 E0C200B2 strh   a1, [a3], 2
00000048 E2511001 subs   a2, a2, 1
0000004C EAFFFFFA b      3Ch
00000050 E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000054 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000058 E1A04002 mov    v1, a3
0000005C E92D000F stmdb  sp!, {a1-a4}
00000060 E3A02000 mov    a3, 0
00000064 E3822C05 orr    a3, a3, 500h
00000068 E0130291 muls   a4, a2, a3
0000006C E0933080 adds   a4, a4, a1, lsl 1
00000070 E3A01000 mov    a2, 0
00000074 E3811602 orr    a2, a2, 200000h
00000078 E0910003 adds   a1, a2, a4
0000007C E1A0A000 mov    v7, a1
00000080 E8BD000F ldmia  sp!, {a1-a4}
00000084 E1A0000A mov    a1, v7
00000088 E1C040B0 strh   v1, [a1]
0000008C E8BD9FF0 ldmia  sp!, {v1-ip,pc}
00000090 E92D5FF0 stmdb  sp!, {v1-ip,lr}
00000094 E1A04003 mov    v1, a4
00000098 E1A05002 mov    v2, a3
0000009C E92D000F stmdb  sp!, {a1-a4}
000000A0 E3A02000 mov    a3, 0
000000A4 E3822C05 orr    a3, a3, 500h
000000A8 E0130291 muls   a4, a2, a3
000000AC E0933080 adds   a4, a4, a1, lsl 1
000000B0 E3A01000 mov    a2, 0
000000B4 E3811602 orr    a2, a2, 200000h
000000B8 E0910003 adds   a1, a2, a4
000000BC E1A0A000 mov    v7, a1
000000C0 E8BD000F ldmia  sp!, {a1-a4}
000000C4 E1A0000A mov    a1, v7
000000C8 E3550000 cmp    v2, 0
000000CC 0A000002 beq    0DCh
000000D0 E0C040B2 strh   v1, [a1], 2
000000D4 E2555001 subs   v2, v2, 1
000000D8 EAFFFFFA b      0C8h
000000DC E8BD9FF0 ldmia  sp!, {v1-ip,pc}
000000E0 E92D5FF0 stmdb  sp!, {v1-ip,lr}
000000E4 E1A04003 mov    v1, a4
000000E8 E1A05002 mov    v2, a3
000000EC E92D000F stmdb  sp!, {a1-a4}
000000F0 E3A02000 mov    a3, 0
000000F4 E3822C05 orr    a3, a3, 500h
000000F8 E0130291 muls   a4, a2, a3
000000FC E0933080 adds   a4, a4, a1, lsl 1
00000100 E3A01000 mov    a2, 0
00000104 E3811602 orr    a2, a2, 200000h
00000108 E0910003 adds   a1, a2, a4
0000010C E1A0A000 mov    v7, a1
00000110 E8BD000F ldmia  sp!, {a1-a4}
00000114 E1A0000A mov    a1, v7
00000118 E3550000 cmp    v2, 0
0000011C 0A000003 beq    130h
00000120 E0D4C0B2 ldrh   ip, [v1], 2
00000124 E0C0C0B2 strh   ip, [a1], 2
00000128 E2555001 subs   v2, v2, 1
0000012C EAFFFFF9 b      118h
00000130 E8BD9FF0 ldmia  sp!, {v1-ip,pc}[/code][b]IMPORT/EXPORT MACROS (IMPORT.INC)[/b][code];;;;;;;;;;;;;;;;;;; IMPORT.INC ;;;;;;;;;;;;;;;;;;;

; write library (.L) file containing
; functions. example:

; export strlen, strcpy, strcmp, strequ

macro export l, [f] {
 common
  local n, ..f
  n=0
 forward
  n=n+1
 common         ; 16 byte header:
  db 'L', 0     ; signature, version=0
  dh n          ; # functions (offset=Ah)
  dw ..f        ; functions begin
  dw 0, 0       ; reserved
 forward        ; array of:
  local l
  l db `f, 0    ; function name
  times \       ; align 24
   24-($-l) \
   db 0
  dw !#f        ; function offset
  dw !#f#.$     ; function size
 common
  while $ mod 4 ; align 4 for ARM
   db 0         ; (it should already
  end while     ; be aligned)
  ..f:          ; functions begin
}     

; load s/pecific functions from library*.L
; into current module. example:

; import string,\
; strlen, strcpy, strcmp, strequ

macro import l, [f] {
 common
  local a, b, c,\
   p, i, n, s, o,\
   fb, found, equal
  virtual at 0            ; virtual file
   p:: file `l#'.L'
  end virtual
  load a byte from p:0    ; signature
  if a<>'L'
   'Invalid signature'
  end if
  load a byte from p:1    ; version
  if a<>0
   'Version must be 0'
  end if
  load n hword \          ; # functions total
   from p:2
  load fb word \          ; functions begin
   from p:4
 forward                  ; iterate through
  local fs                ; function names...
  virtual at 0
   fs::                   ; current function
   i=$                    ; structure:
   db `f, 0               ; name
   times \                ; align 24
    24-($-i) db 0
   dw 0, 0                ; offset, size
  end virtual
  i=0
  repeat n                ; search functions
   equal=1                ; for name...
   found=0
   repeat 6-1             ; read and compare
    load a word from p:\  ; names. 24 bytes,
     16+(i*32)+((%-1)*4)  ; 4 a time
    load b word from \
     fs:((%-1)*4)
    if a<>b               ; while equal
     equal=0
     break
    end if
   end repeat
   if equal
    found=16+(i*32)       ; offset
    break
   end if
   i=i+1
  end repeat
  if found=0
   'Name not found:' f
  end if
  load o word from \      ; read offset
   p:found+24
  load s word from \      ; and size
   p:found+28
  store word o at fs:24   ; store in current
  store word s at fs:28   ; function structure
  !#f:                    ; !name:
  repeat s/4              ; extract found
   load a word from \     ; function from file
    p:o+((%-1)*4)         ; 4 bytes at a time
   dw a                   ; insert <here>
  end repeat
  macro f [ps] \{         ; fast-call macro
   macro list.e a, [p] \  ; store register
    \\{ \forward \        ; names in list
     a equ p \\}
   list.e ?rs,\
    v4,v3,v2,v1,\
    a4,a3,a2,a1
   \forward
     match x, ?rs         ; restore register
      \\{ restore ?rs     ; names
      let x=ps \\}        ; send parameter
   \common
     bl !\#f
  \}
 common
  ; ...
}[/code]

[LIBRARY IMAGE]