1 /* 2 * Copyright 2019-2020, Adrien Destugues <pulkomandy@pulkomandy.tk> 3 * Copyright 2010, Ithamar R. Adema <ithamar.adema@team-embedded.nl> 4 * Copyright 2009, Johannes Wischert, johanneswi@gmail.com. 5 * Copyright 2005, Ingo Weinhold <bonefish@cs.tu-berlin.de>. 6 * Copyright 2002, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the MIT License. 8 */ 9 10 11 #include <KernelExport.h> 12 13 #include <elf_priv.h> 14 #include <boot/elf.h> 15 #include <arch/elf.h> 16 17 18 //#define TRACE_ARCH_ELF 19 #ifdef TRACE_ARCH_ELF 20 # define TRACE(x) dprintf x 21 # define CHATTY 1 22 #else 23 # define TRACE(x) ; 24 # define CHATTY 0 25 #endif 26 27 28 #ifndef _BOOT_MODE 29 static bool 30 is_in_image(struct elf_image_info *image, addr_t address) 31 { 32 return (address >= image->text_region.start 33 && address < image->text_region.start + image->text_region.size) 34 || (address >= image->data_region.start 35 && address < image->data_region.start + image->data_region.size); 36 } 37 #endif // !_BOOT_MODE 38 39 40 #ifdef _BOOT_MODE 41 status_t 42 boot_arch_elf_relocate_rel(struct preloaded_elf64_image *image, Elf64_Rel *rel, 43 int rel_len) 44 #else 45 int 46 arch_elf_relocate_rel(struct elf_image_info *image, 47 struct elf_image_info *resolve_image, Elf64_Rel *rel, int rel_len) 48 #endif 49 { 50 // there are no rel entries in M68K elf 51 return B_NO_ERROR; 52 } 53 54 55 static inline void 56 write_word32(addr_t P, Elf64_Word value) 57 { 58 *(Elf64_Word*)P = value; 59 } 60 61 62 static inline void 63 write_word64(addr_t P, Elf64_Xword value) 64 { 65 *(Elf64_Xword*)P = value; 66 } 67 68 69 static inline void 70 write_hi30(addr_t P, Elf64_Word value) 71 { 72 *(Elf64_Word*)P |= value >> 2; 73 } 74 75 76 static inline void 77 write_hi22(addr_t P, Elf64_Word value) 78 { 79 *(Elf64_Word*)P |= value >> 10; 80 } 81 82 83 static inline void 84 write_lo10(addr_t P, Elf64_Word value) 85 { 86 *(Elf64_Word*)P |= value & 0x3ff; 87 } 88 89 90 static inline void 91 write_hh22(addr_t P, Elf64_Xword value) 92 { 93 *(Elf64_Word*)P |= value >> 42; 94 } 95 96 97 static inline void 98 write_hm10(addr_t P, Elf64_Xword value) 99 { 100 *(Elf64_Word*)P |= (value >> 32) & 0x3ff; 101 } 102 103 104 #ifdef _BOOT_MODE 105 status_t 106 boot_arch_elf_relocate_rela(struct preloaded_elf64_image *image, 107 Elf64_Rela *rel, int rel_len) 108 #else 109 int 110 arch_elf_relocate_rela(struct elf_image_info *image, 111 struct elf_image_info *resolve_image, Elf64_Rela *rel, int rel_len) 112 #endif 113 { 114 int i; 115 Elf64_Sym *sym; 116 int vlErr; 117 118 Elf64_Addr S = 0; // symbol address 119 //addr_t R = 0; // section relative symbol address 120 121 //addr_t G = 0; // GOT address 122 //addr_t L = 0; // PLT address 123 124 #define P ((addr_t)(image->text_region.delta + rel[i].r_offset)) 125 #define A ((addr_t)rel[i].r_addend) 126 #define B (image->text_region.delta) 127 128 // TODO: Get the GOT address! 129 #define REQUIRE_GOT \ 130 if (G == 0) { \ 131 dprintf("arch_elf_relocate_rela(): Failed to get GOT address!\n"); \ 132 return B_ERROR; \ 133 } 134 135 // TODO: Get the PLT address! 136 #define REQUIRE_PLT \ 137 if (L == 0) { \ 138 dprintf("arch_elf_relocate_rela(): Failed to get PLT address!\n"); \ 139 return B_ERROR; \ 140 } 141 142 for (i = 0; i * (int)sizeof(Elf64_Rela) < rel_len; i++) { 143 #if CHATTY 144 dprintf("looking at rel type %" PRIu64 ", offset 0x%lx, sym 0x%lx, " 145 "addend 0x%lx\n", ELF64_R_TYPE(rel[i].r_info), rel[i].r_offset, 146 ELF64_R_SYM(rel[i].r_info), rel[i].r_addend); 147 #endif 148 // Relocation types and what to do with them are defined in Oracle docs 149 // Documentation Home > Linker and Libraries Guide 150 // > Chapter 7 Object File Format > File Format > Relocation Sections 151 // > Relocation Types (Processor-Specific) > SPARC: Relocation Types 152 // https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-24/index.html 153 // https://docs.oracle.com/cd/E19120-01/open.solaris/819-0690/chapter6-24-1/index.html 154 switch (ELF64_R_TYPE(rel[i].r_info)) { 155 case R_SPARC_WDISP30: 156 case R_SPARC_HI22: 157 case R_SPARC_LO10: 158 case R_SPARC_HH22: 159 case R_SPARC_LM22: 160 case R_SPARC_HM10: 161 case R_SPARC_GLOB_DAT: 162 case R_SPARC_JMP_SLOT: 163 case R_SPARC_64: 164 sym = SYMBOL(image, ELF64_R_SYM(rel[i].r_info)); 165 #ifdef _BOOT_MODE 166 vlErr = boot_elf_resolve_symbol(image, sym, &S); 167 #else 168 vlErr = elf_resolve_symbol(image, sym, resolve_image, &S); 169 #endif 170 if (vlErr < 0) { 171 dprintf("%s(): Failed to relocate " 172 "entry index %d, rel type %" PRIu64 ", offset 0x%lx, " 173 "sym 0x%lx, addend 0x%lx\n", __FUNCTION__, i, 174 ELF64_R_TYPE(rel[i].r_info), 175 rel[i].r_offset, ELF64_R_SYM(rel[i].r_info), 176 rel[i].r_addend); 177 return vlErr; 178 } 179 break; 180 } 181 182 switch (ELF64_R_TYPE(rel[i].r_info)) { 183 case R_SPARC_WDISP30: 184 { 185 write_hi30(P, S + A - P); 186 } 187 case R_SPARC_HI22: 188 case R_SPARC_LM22: 189 { 190 write_hi22(P, S + A); 191 break; 192 } 193 case R_SPARC_LO10: 194 { 195 write_lo10(P, S + A); 196 break; 197 } 198 case R_SPARC_HH22: 199 { 200 write_hh22(P, S + A); 201 break; 202 } 203 case R_SPARC_HM10: 204 { 205 write_hm10(P, S + A); 206 break; 207 } 208 case R_SPARC_GLOB_DAT: 209 { 210 write_word64(P, S + A); 211 break; 212 } 213 case R_SPARC_JMP_SLOT: 214 { 215 // Created by the link-editor for dynamic objects to provide 216 // lazy binding. The relocation offset member gives the 217 // location of a procedure linkage table entry. The runtime 218 // linker modifies the procedure linkage table entry to 219 // transfer control to the designated symbol address. 220 addr_t jumpOffset = S - (P + 8); 221 if ((jumpOffset & 0xc0000000) != 0 222 && (~jumpOffset & 0xc0000000) != 0) { 223 // Offset > 30 bit. 224 // TODO: Implement! 225 // See https://docs.oracle.com/cd/E26502_01/html/E26507/chapter6-1235.html 226 // examples .PLT102 and .PLT103 227 dprintf("arch_elf_relocate_rela(): R_SPARC_JMP_SLOT: " 228 "Offsets > 30 bit currently not supported!\n"); 229 dprintf("jumpOffset: %p\n", (void*)jumpOffset); 230 return B_ERROR; 231 } else { 232 uint32* instructions = (uint32*)P; 233 // We need to use a call instruction because it has a lot 234 // of space for the destination (30 bits). However, it 235 // erases o7, which we don't want. 236 // We could avoid this with a JMPL if the displacement was 237 // small enough, but it probably isn't. 238 // So, we store o7 in g1 before the call, and restore it 239 // in the branch delay slot. Crazy, but it works! 240 instructions[0] = 0x01000000; // NOP to preserve the alignment? 241 instructions[1] = 0x8210000f; // MOV %o7, %g1 242 instructions[2] = 0x40000000 | ((jumpOffset >> 2) & 0x3fffffff); 243 instructions[3] = 0x9e100001; // MOV %g1, %o7 244 } 245 break; 246 } 247 case R_SPARC_RELATIVE: 248 { 249 write_word32(P, B + A); 250 break; 251 } 252 case R_SPARC_64: 253 { 254 write_word64(P, S + A); 255 break; 256 } 257 default: 258 dprintf("arch_elf_relocate_rela: unhandled relocation type %" 259 PRIu64 "\n", ELF64_R_TYPE(rel[i].r_info)); 260 return B_ERROR; 261 } 262 } 263 return B_OK; 264 } 265