# Zero-initialisation code

The Zero-initialisation code is as follows:

``

    ZeroInit
        NOP                            ; or

`

        SUB    ip, lr, pc                            ; base+12+[PSR]-(ZeroInit+12+[PSR])
                                ; = base-ZeroInit
        ADD    ip, pc, ip                            ; base-ZeroInit+ZeroInit+16 = base+16
        LDMIB  ip, {r0,r1,r2,r4}                            ; various sizes
        SUB    ip, ip, #16                            ; image base
        ADD    ip, ip, r0                            ; + rO size
        ADD    ip, ip, r1                            ; + RW size = base of 0-init area
        MOV    r0, #0
        MOV    r1, #0
        MOV    r2, #0
        MOV    r3, #0
        CMPS   r4, #0
    00  MOVLE  pc, lr                            ; nothing left to do
        STMIA  ip!, {r0,r1,r2,r3}                            ; always zero a multiple of 16 bytes
        SUBS   r4, r4, #16
        B      %B00

`

## Self-move and self-relocation code

This code is added to the end of an AIF image by the linker, immediately before the list of relocations (which is terminated by -1). Note that the code is entered via a BL from the second word of the AIF header so, on entry, r14 -> AIFHeader + 8. In 26-bit ARM modes, r14 also contains a copy of the PSR flags.

On entry, the relocation code calculates the address of the AIF header (in a CPU-independent fashion) and decides whether the image needs to be moved. If the image doesn't need to be moved, the code branches to RelocateOnly.

``

    RelocCode
        NOP                          ; required by ensure_byte_order()
                              ; and used below.
        SUB    ip, lr, pc                         ; base+8+[PSR]-(RelocCode+12+[PSR])
                              ; = base-4-RelocCode
        ADD    ip, pc, ip                         ; base-4-RelocCode+RelocCode+16 = base+12
        SUB    ip, ip, #12                         ; -> header address
        LDR    r0, RelocCode                         ; NOP
        STR    r0, [ip, #4]                        ; won't be called again on image re-entry
        LDR    r9, [ip, #&2C]                         ; min free space requirement
        CMPS   r9, #0                          ; 0 => no move, just relocate
        BEQ    RelocateOnly

If the image needs to be moved up memory, then the top of memory has to be found. Here, a system service (SWI 0x10) is called to return the address of the top of memory in r1. This is, of course, system specific and should be replaced by whatever code sequence is appropriate to the environment.

``

        LDR    r0, [ip, #&20]                            ;image zero-init size
        ADD    r9, r9, r0                            ;space to leave = min free + zero init
        SWI    #&10                            ;return top of memory in r1.

The following code calculates the length of the image inclusive of its relocation data, and decides whether a move up store is possible.

``

        ADR    r2, End                            ; -> End
    01  LDR    r0, [r2], #4                            ; load relocation offset, increment r2
        CMNS   r0, #1                            ; terminator?
        BNE    %B01                            ; No, so loop again
        SUB    r3, r1, r9                            ; MemLimit - freeSpace
        SUBS   r0, r3, r2                            ; amount to move by
        BLE    RelocateOnly                            ; not enough space to move...
        BIC    r0, r0, #15                            ; a multiple of 16...
        ADD    r3, r2, r0                            ; End + shift
        ADR    r8, %F02                            ; intermediate limit for copy-up

Finally, the image copies itself four words at a time, being careful about the direction of copy, and jumping to the copied copy code as soon as it has copied itself.

``

    02  LDMDB  r2!, {r4-r7}
        STMDB  r3!, {r4-r7}
        CMPS   r2, r8                            ; copied the copy loop?
        BGT    %B02                            ; not yet
        ADD    r4, pc, r0
        MOV    pc, r4                            ; jump to copied copy code
    03  LDMDB  r2!, {r4-r7}
        STMDB  r3!, {r4-r7}
        CMPS   r2, ip                            ; copied everything?
        BGT    %B03                            ; not yet
        ADD    ip, ip, r0                            ; load address of code
        ADD    lr, lr, r0                            ; relocated return address

Whether the image has moved itself or not, control eventually arrives here, where the list of locations to be relocated is processed. Each location is word sized and is relocated by the difference between the address the image was loaded at (the address of the AIF header) and the address the image was linked at (stored at offset 0x28 in the AIF header).

``

    RelocateOnly
        LDR    r1, [ip, #&28]                                ; header + 0x28
                                    ; = code base set by Link
        SUBS   r1, ip, r1                                ; relocation offset
        MOVEQ  pc, lr                                ; relocate by 0 so nothing to do
        STR    ip, [ip, #&28]                                ; new image base
                                    ; = actual load address
        ADR    r2, End                                ; start of reloc list
    04  LDR    r0, [r2], #4                                ; offset of word to relocate
        CMNS   r0, #1                                ; terminator?
        MOVEQ  pc, lr                                ; yes => return
        LDR    r3, [ip, r0]                                ; word to relocate
        ADD    r3, r3, r1                                ; relocate it
        STR    r3, [ip, r0]                                ; store it back
        B      %B04                                ; and do the next one
    End                                ; List of offsets of locations to
                                    ; relocate starts here,
                                    ; terminated by -1.

You can customise the self-relocation and self-moving code generated by armlink by providing your version of it in an area called AIF_RELOC in the first object file in armlink's input list.