reloc_arm.c (7591B)
1 /* RelocKind <-> ARM (Thumb-2) ELF reloc-type mapping (ELFCLASS32). 2 * 3 * Self-contained (ARM has no 64-bit ELF sibling). Data words reuse the neutral 4 * R_ABS32 / R_REL32 / R_ABS16 / R_ABS8 kinds; only the instruction-embedded 5 * Thumb-2 kinds get arch entries. The split-immediate byte patcher lives in 6 * src/arch/arm32/reloc.c. */ 7 #include "core/bytes.h" 8 #include "obj/elf/elf.h" 9 #include "obj/obj.h" 10 11 u32 elf_arm_reloc_to(u32 kind /* RelocKind */) { 12 switch (kind) { 13 case R_NONE: 14 return ELF_R_ARM_NONE; 15 case R_ABS32: 16 return ELF_R_ARM_ABS32; 17 case R_REL32: 18 case R_PC32: 19 return ELF_R_ARM_REL32; /* PC-rel data collapses to REL32 */ 20 case R_ABS16: 21 return ELF_R_ARM_ABS16; 22 case R_ABS8: 23 return ELF_R_ARM_ABS8; 24 case R_ARM_THM_CALL: 25 return ELF_R_ARM_THM_CALL; 26 case R_ARM_THM_JUMP24: 27 return ELF_R_ARM_THM_JUMP24; 28 case R_ARM_THM_JUMP19: 29 return ELF_R_ARM_THM_JUMP19; 30 case R_ARM_THM_MOVW_ABS_NC: 31 return ELF_R_ARM_THM_MOVW_ABS_NC; 32 case R_ARM_THM_MOVT_ABS: 33 return ELF_R_ARM_THM_MOVT_ABS; 34 case R_ARM_THM_MOVW_PREL_NC: 35 return ELF_R_ARM_THM_MOVW_PREL_NC; 36 case R_ARM_THM_MOVT_PREL: 37 return ELF_R_ARM_THM_MOVT_PREL; 38 case R_ARM_TLS_LE32: 39 return ELF_R_ARM_TLS_LE32; 40 default: 41 return ELF_R_ARM_NONE; 42 } 43 } 44 45 u32 elf_arm_reloc_from(u32 elf_type) { 46 switch (elf_type) { 47 case ELF_R_ARM_NONE: 48 return R_NONE; 49 case ELF_R_ARM_ABS32: 50 return R_ABS32; 51 case ELF_R_ARM_REL32: 52 return R_REL32; 53 case ELF_R_ARM_ABS16: 54 return R_ABS16; 55 case ELF_R_ARM_ABS8: 56 return R_ABS8; 57 case ELF_R_ARM_THM_CALL: 58 return R_ARM_THM_CALL; 59 case ELF_R_ARM_THM_JUMP24: 60 return R_ARM_THM_JUMP24; 61 case ELF_R_ARM_THM_JUMP19: 62 return R_ARM_THM_JUMP19; 63 case ELF_R_ARM_THM_MOVW_ABS_NC: 64 return R_ARM_THM_MOVW_ABS_NC; 65 case ELF_R_ARM_THM_MOVT_ABS: 66 return R_ARM_THM_MOVT_ABS; 67 case ELF_R_ARM_THM_MOVW_PREL_NC: 68 return R_ARM_THM_MOVW_PREL_NC; 69 case ELF_R_ARM_THM_MOVT_PREL: 70 return R_ARM_THM_MOVT_PREL; 71 case ELF_R_ARM_TLS_LE32: 72 return R_ARM_TLS_LE32; 73 default: 74 return (u32)-1; /* reader diagnoses unsupported wire types */ 75 } 76 } 77 78 const char* elf_arm_reloc_name(u32 elf_type) { 79 switch (elf_type) { 80 case ELF_R_ARM_NONE: 81 return "R_ARM_NONE"; 82 case ELF_R_ARM_ABS32: 83 return "R_ARM_ABS32"; 84 case ELF_R_ARM_REL32: 85 return "R_ARM_REL32"; 86 case ELF_R_ARM_ABS16: 87 return "R_ARM_ABS16"; 88 case ELF_R_ARM_ABS8: 89 return "R_ARM_ABS8"; 90 case ELF_R_ARM_THM_CALL: 91 return "R_ARM_THM_CALL"; 92 case ELF_R_ARM_THM_JUMP24: 93 return "R_ARM_THM_JUMP24"; 94 case ELF_R_ARM_THM_JUMP19: 95 return "R_ARM_THM_JUMP19"; 96 case ELF_R_ARM_THM_MOVW_ABS_NC: 97 return "R_ARM_THM_MOVW_ABS_NC"; 98 case ELF_R_ARM_THM_MOVT_ABS: 99 return "R_ARM_THM_MOVT_ABS"; 100 case ELF_R_ARM_THM_MOVW_PREL_NC: 101 return "R_ARM_THM_MOVW_PREL_NC"; 102 case ELF_R_ARM_THM_MOVT_PREL: 103 return "R_ARM_THM_MOVT_PREL"; 104 case ELF_R_ARM_TLS_LE32: 105 return "R_ARM_TLS_LE32"; 106 default: 107 return NULL; 108 } 109 } 110 111 /* Decode the float ABI from ARM ELF e_flags (EF_ARM_ABI_FLOAT_*). The two 112 * flags are independent bits, not a mask field. */ 113 KitFloatAbi elf_arm_float_abi_from_e_flags(u32 e_flags) { 114 if (e_flags & EF_ARM_ABI_FLOAT_HARD) return KIT_FLOAT_ABI_SINGLE; 115 if (e_flags & EF_ARM_ABI_FLOAT_SOFT) return KIT_FLOAT_ABI_SOFT; 116 return KIT_FLOAT_ABI_DEFAULT; 117 } 118 119 u32 elf_arm_float_abi_to_e_flags(KitFloatAbi abi) { 120 /* Match the ARM toolchain convention (clang/gas): only hard-float objects 121 * set a float-ABI bit; soft/agnostic objects leave both unset (soft is the 122 * default). Setting EF_ARM_ABI_FLOAT_SOFT would make every kit object 123 * mismatch the ecosystem's soft objects under the linker's e_flags check. */ 124 switch (abi) { 125 case KIT_FLOAT_ABI_SINGLE: 126 case KIT_FLOAT_ABI_DOUBLE: 127 return EF_ARM_ABI_FLOAT_HARD; 128 default: 129 return 0u; /* soft / agnostic: no float-ABI bit */ 130 } 131 } 132 133 /* A 32-bit Thumb-2 instruction is two independently-little-endian 16-bit 134 * halfwords, the HIGH halfword FIRST in memory (matches arm_rd_t32 in 135 * src/arch/arm32/reloc.c). The returned value has hw1 in bits [31:16]. */ 136 static u32 arm_rd_t32_field(const u8* p) { 137 return ((u32)rd_u16_le(p) << 16) | (u32)rd_u16_le(p + 2); 138 } 139 140 static i32 sign_extend(u32 v, u32 bits) { 141 u32 m = 1u << (bits - 1); 142 return (i32)((v ^ m) - m); 143 } 144 145 /* Reconstruct the implicit addend a REL relocation carries in its field ā the 146 * inverse of the patchers in src/arch/arm32/reloc.c. For REL there is no 147 * r_addend slot, so kit's own linker must recover the same addend a 148 * field-reading linker (ld.lld, GNU ld) would. `field` points at the 149 * relocated location; `width` is its byte width (4 for data words and Thumb-2 150 * instructions). Mirrors the AAELF32 REL addend conventions. */ 151 i64 elf_arm_reloc_field_addend(u32 kind /* RelocKind */, const u8* field, 152 u32 width) { 153 switch (kind) { 154 case R_ABS32: 155 case R_REL32: 156 case R_PC32: 157 /* Plain little-endian data word; the addend sits in the field verbatim 158 * (api_data_encode_addend pre-wrote it on emit). */ 159 return width >= 4 ? (i64)(i32)rd_u32_le(field) : 0; 160 case R_ABS16: 161 return (i64)(i16)rd_u16_le(field); 162 case R_ABS8: 163 return (i64)(i8)field[0]; 164 case R_ARM_THM_CALL: 165 case R_ARM_THM_JUMP24: { 166 /* BL/B.W 25-bit field {S,I1,I2,imm10,imm11}, JāI XOR-with-S. The patcher 167 * wrote disp = (S&~1)+A-P-4; at read time S=P=0, so A = disp + 4. The 168 * canonical placeholder (disp=-4) thus decodes to addend 0. */ 169 u32 instr = arm_rd_t32_field(field); 170 u32 sbit = (instr >> 26) & 1u; 171 u32 j1 = (instr >> 13) & 1u, j2 = (instr >> 11) & 1u; 172 u32 i1 = (~(j1 ^ sbit)) & 1u, i2 = (~(j2 ^ sbit)) & 1u; 173 u32 imm10 = (instr >> 16) & 0x3ffu, imm11 = instr & 0x7ffu; 174 u32 off = (sbit << 24) | (i1 << 23) | (i2 << 22) | (imm10 << 12) | 175 (imm11 << 1); 176 return (i64)sign_extend(off, 25) + 4; 177 } 178 case R_ARM_THM_JUMP19: { 179 /* B<cond>.W 21-bit field {S,J2,J1,imm6,imm11} (no XOR-with-S). */ 180 u32 instr = arm_rd_t32_field(field); 181 u32 sbit = (instr >> 26) & 1u; 182 u32 j2 = (instr >> 11) & 1u, j1 = (instr >> 13) & 1u; 183 u32 imm6 = (instr >> 16) & 0x3fu, imm11 = instr & 0x7ffu; 184 u32 off = 185 (sbit << 20) | (j2 << 19) | (j1 << 18) | (imm6 << 12) | (imm11 << 1); 186 return (i64)sign_extend(off, 21) + 4; 187 } 188 case R_ARM_THM_MOVW_ABS_NC: 189 case R_ARM_THM_MOVT_ABS: 190 case R_ARM_THM_MOVW_PREL_NC: 191 case R_ARM_THM_MOVT_PREL: { 192 /* MOVW/MOVT 16-bit immediate scattered imm4:i:imm3:imm8. Each reloc 193 * carries only one 16-bit half of (S+A); at read time S=0 so the field 194 * is (A & 0xffff) for MOVW or ((A>>16) & 0xffff) for MOVT. Current arm32 195 * codegen always emits addend 0 here (a constant byte offset folds into 196 * a separate add), so this decodes to 0. A non-zero addend split across 197 * the MOVW/MOVT pair would need both halves recombined into one 32-bit 198 * A for kit-ld's (S+A) patcher ā a Phase-2+ refinement; lld already 199 * handles the per-half group-relocation form. */ 200 u32 instr = arm_rd_t32_field(field); 201 u32 imm4 = (instr >> 16) & 0xfu, i = (instr >> 26) & 1u; 202 u32 imm3 = (instr >> 12) & 7u, imm8 = instr & 0xffu; 203 u32 imm16 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8; 204 return (i64)imm16; 205 } 206 default: 207 return 0; 208 } 209 }