]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[riscv] Use compressed relocation records
authorMichael Brown <mcb30@ipxe.org>
Tue, 6 May 2025 13:53:29 +0000 (14:53 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 6 May 2025 14:01:45 +0000 (15:01 +0100)
Use compressed relocation records instead of raw Elf_Rela records.
This saves around 15% of the total binary size for the all-drivers
image bin-riscv64/ipxe.sbi.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/riscv/Makefile.sbi
src/arch/riscv/prefix/libprefix.S
src/arch/riscv/prefix/sbiprefix.S
src/arch/riscv/scripts/sbi.lds

index dee1b6e5d262036f6152bedb1d4c06854a8ce651..a10680eafe8ad853fff9bea46865d36b4c7ae2da 100644 (file)
@@ -5,7 +5,7 @@
 # prefix code.
 #
 CFLAGS         += -mcmodel=medany -fpie
-LDFLAGS                += -pie --no-dynamic-linker
+LDFLAGS                += -pie --no-dynamic-linker -z combreloc
 
 # Linker script
 #
index f268def1a03fd0699e179dea44290b17bb8aa560..43a92330300faa44fc0a0097d570164cded545d2 100644 (file)
        .section ".note.GNU-stack", "", @progbits
        .text
 
+       /* Virtual address of _prefix
+        *
+        * This will be updated if runtime relocations are applied.
+        */
+       .section ".rodata.prefix_virt", "a", @progbits
+prefix_virt:
+       .dword  _prefix
+       .size   prefix_virt, . - prefix_virt
+
 /*****************************************************************************
  *
- * Apply relocation records
+ * Apply compressed relocation records
  *
  *****************************************************************************
  *
- * Apply relocation records from .rel.dyn to fix up iPXE to run at its
- * current address.
+ * Apply compressed relocation records to fix up iPXE to run at its
+ * current virtual address.
  *
  * This function must run before .bss is zeroed (since the relocation
  * records are overlaid with .bss).  It does not require a valid stack
  *
  */
 
-/* Relative relocation type */
-#define R_RISCV_RELATIVE 3
-
-       /* Layout of a relocation record */
-       .struct 0
-rela_offset:   .space ( __riscv_xlen / 8 )
-rela_type:     .space ( __riscv_xlen / 8 )
-rela_addend:   .space ( __riscv_xlen / 8 )
-rela_len:
-       .previous
+/** Number of bits in a skip value */
+#define ZREL_SKIP_BITS 19
 
        .section ".prefix.apply_relocs", "ax", @progbits
        .globl  apply_relocs
 apply_relocs:
+       /* Register usage:
+        *
+        * a0 - relocation addend
+        * a1 - current relocation target address
+        * a2 - current relocation record pointer
+        * a3 - current relocation record value
+        * a4 - number of bits remaining in current relocation record
+        */
+       la      a1, _prefix
+       la      a2, _edata
 
-       /* Get relocation records */
-       la      t0, _reloc
-       la      t1, _ereloc
-
-       /* Determine current location */
-       la      t2, reloc_base
-       LOADN   t2, (t2)
-       sub     t2, t0, t2
-
-1:     /* Read relocation record */
-       LOADN   t3, rela_offset(t0)
-       LOADN   t4, rela_type(t0)
-       LOADN   t5, rela_addend(t0)
-
-       /* Check relocation type */
-       addi    t4, t4, -R_RISCV_RELATIVE
-       bnez    t4, 2f
-
-       /* Apply relocation */
-       add     t3, t3, t2
-       add     t5, t5, t2
-       STOREN  t5, (t3)
-2:
-       /* Loop until done */
-       addi    t0, t0, rela_len
-       blt     t0, t1, 1b
-
+       /* Calculate relocation addend */
+       la      t0, prefix_virt
+       LOADN   a0, (t0)
+       sub     a0, a1, a0
+
+       /* Skip applying relocations if addend is zero */
+       beqz    a0, apply_relocs_done
+
+apply_relocs_loop:
+       /* Read new relocation record */
+       LOADN   a3, (a2)
+       addi    a2, a2, ( __riscv_xlen / 8 )
+       li      a4, ( __riscv_xlen - 1 )
+
+       /* Consume and apply skip, if present (i.e. if MSB=0) */
+       bltz    a3, 1f
+       addi    a4, a4, -ZREL_SKIP_BITS
+       srli    t0, a3, ( __riscv_xlen - ( ZREL_SKIP_BITS + 1 ) )
+       slli    t0, t0, ( ( __riscv_xlen / 32 ) + 1 )
+       add     a1, a1, t0
+1:
+       /* Apply relocations corresponding to set bits in record */
+1:     andi    t0, a3, 1
+       beqz    t0, 2f
+       LOADN   t1, (a1)
+       add     t1, t1, a0
+       STOREN  t1, (a1)
+2:     addi    a1, a1, ( __riscv_xlen / 8 )
+       srli    a3, a3, 1
+       addi    a4, a4, -1
+       bnez    a4, 1b
+
+       /* Loop until we have reached a terminator record (MSB=0, offset=0) */
+       bnez    a3, apply_relocs_loop
+
+apply_relocs_done:
        /* Return to caller */
        ret
        .size   apply_relocs, . - apply_relocs
 
-       /* Link-time address of _reloc */
-       .section ".rodata", "a", @progbits
-reloc_base:
-       .dword  _reloc_base
-       .size   reloc_base, . - reloc_base
-
 /*****************************************************************************
  *
  * Enable paging
@@ -187,12 +201,6 @@ reloc_base:
        .globl  enable_paging
        .equ    enable_paging, _C2 ( enable_paging_, __riscv_xlen )
 
-       /* Link-time address of _prefix */
-       .section ".rodata.prefix_virt", "a", @progbits
-prefix_virt:
-       .dword  _prefix
-       .size   prefix_virt, . - prefix_virt
-
 /*****************************************************************************
  *
  * Enable 64-bit paging
index ccf8b0743fcba8fb53a0685ac4b5ff18dfb926cc..f590b324bdb1c892c6fa9ea836d19f6a4300cf0a 100644 (file)
@@ -41,6 +41,9 @@
 #define SBI_SRST_SYSTEM_RESET 0x00
 #define SBI_RESET_COLD 0x00000001
 
+/* ELF machine type */
+#define EM_RISCV 243
+
        /*
         * Display progress message via debug console
         */
@@ -127,5 +130,12 @@ _sbi_start:
        .section ".zinfo", "a", @progbits
        .ascii  "COPY"
        .word   0
-       .word   _sbi_filesz
+       .word   _filesz
        .word   1
+       .ascii  "BASE"
+       .word   0
+       .dword  _base
+       .ascii  "ZREL"
+       .word   _reloc_offset
+       .word   _reloc_filesz
+       .word   EM_RISCV
index 21fba5d3da13f2dc0f6a4c4d0182e84f98160257..efda0aa81810e1710c5062ff291f22d652243965 100644 (file)
@@ -61,7 +61,6 @@ SECTIONS {
 
        /* Runtime relocations (discarded after use) */
        .rela.dyn {
-           _reloc = .;
            *(.rela)
            *(.rela.dyn)
        }
@@ -88,25 +87,15 @@ SECTIONS {
        }
     }
 
-    /* Absolute link-time address of _reloc
-     *
-     * The runtime relocator needs to know the link-time addresses.
-     * Since RISC-V uses .rela (rather than .rel), the only way to
-     * expose this to the relocator is via an absolute symbol.
-     */
-    _reloc_base = ABSOLUTE ( _reloc );
+    /* Base virtual address */
+    _base = ABSOLUTE ( _prefix );
 
-    /* Calculate end of relocations
-     *
-     * This cannot be done by placing "_ereloc = .;" inside the
-     * .rela.dyn section, since the dynamic relocations are not
-     * present in the input sections but are instead generated during
-     * linking.
-     */
-    _ereloc = ( _reloc + __load_stop_reladyn - __load_start_reladyn );
+    /* Relocations */
+    _reloc_offset = ( LOADADDR ( .rela.dyn ) - LOADADDR ( .prefix ) );
+    _reloc_filesz = SIZEOF ( .rela.dyn );
 
     /* Length of initialised data */
-    _sbi_filesz = ( ABSOLUTE ( _ereloc ) - ABSOLUTE ( _prefix ) );
+    _filesz = ( ABSOLUTE ( _edata ) - ABSOLUTE ( _prefix ) );
 
     /* Unwanted sections */
     /DISCARD/ : {