1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <stdio.h> 4 #include <stdarg.h> 5 #include <stdlib.h> 6 #include <stdint.h> 7 #include <inttypes.h> 8 #include <string.h> 9 #include <errno.h> 10 #include <unistd.h> 11 #include <elf.h> 12 #include <byteswap.h> 13 #define USE_BSD 14 #include <endian.h> 15 16 #define ELF_BITS 64 17 18 #define ELF_MACHINE EM_S390 19 #define ELF_MACHINE_NAME "IBM S/390" 20 #define SHT_REL_TYPE SHT_RELA 21 #define Elf_Rel Elf64_Rela 22 23 #define ELF_CLASS ELFCLASS64 24 #define ELF_ENDIAN ELFDATA2MSB 25 #define ELF_R_SYM(val) ELF64_R_SYM(val) 26 #define ELF_R_TYPE(val) ELF64_R_TYPE(val) 27 #define ELF_ST_TYPE(o) ELF64_ST_TYPE(o) 28 #define ELF_ST_BIND(o) ELF64_ST_BIND(o) 29 #define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o) 30 31 #define ElfW(type) _ElfW(ELF_BITS, type) 32 #define _ElfW(bits, type) __ElfW(bits, type) 33 #define __ElfW(bits, type) Elf##bits##_##type 34 35 #define Elf_Addr ElfW(Addr) 36 #define Elf_Ehdr ElfW(Ehdr) 37 #define Elf_Phdr ElfW(Phdr) 38 #define Elf_Shdr ElfW(Shdr) 39 #define Elf_Sym ElfW(Sym) 40 41 static Elf_Ehdr ehdr; 42 static unsigned long shnum; 43 static unsigned int shstrndx; 44 45 struct relocs { 46 uint32_t *offset; 47 unsigned long count; 48 unsigned long size; 49 }; 50 51 static struct relocs relocs64; 52 #define FMT PRIu64 53 54 struct section { 55 Elf_Shdr shdr; 56 struct section *link; 57 Elf_Rel *reltab; 58 }; 59 60 static struct section *secs; 61 62 #if BYTE_ORDER == LITTLE_ENDIAN 63 #define le16_to_cpu(val) (val) 64 #define le32_to_cpu(val) (val) 65 #define le64_to_cpu(val) (val) 66 #define be16_to_cpu(val) bswap_16(val) 67 #define be32_to_cpu(val) bswap_32(val) 68 #define be64_to_cpu(val) bswap_64(val) 69 #endif 70 71 #if BYTE_ORDER == BIG_ENDIAN 72 #define le16_to_cpu(val) bswap_16(val) 73 #define le32_to_cpu(val) bswap_32(val) 74 #define le64_to_cpu(val) bswap_64(val) 75 #define be16_to_cpu(val) (val) 76 #define be32_to_cpu(val) (val) 77 #define be64_to_cpu(val) (val) 78 #endif 79 80 static uint16_t elf16_to_cpu(uint16_t val) 81 { 82 if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 83 return le16_to_cpu(val); 84 else 85 return be16_to_cpu(val); 86 } 87 88 static uint32_t elf32_to_cpu(uint32_t val) 89 { 90 if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB) 91 return le32_to_cpu(val); 92 else 93 return be32_to_cpu(val); 94 } 95 96 #define elf_half_to_cpu(x) elf16_to_cpu(x) 97 #define elf_word_to_cpu(x) elf32_to_cpu(x) 98 99 static uint64_t elf64_to_cpu(uint64_t val) 100 { 101 return be64_to_cpu(val); 102 } 103 104 #define elf_addr_to_cpu(x) elf64_to_cpu(x) 105 #define elf_off_to_cpu(x) elf64_to_cpu(x) 106 #define elf_xword_to_cpu(x) elf64_to_cpu(x) 107 108 static void die(char *fmt, ...) 109 { 110 va_list ap; 111 112 va_start(ap, fmt); 113 vfprintf(stderr, fmt, ap); 114 va_end(ap); 115 exit(1); 116 } 117 118 static void read_ehdr(FILE *fp) 119 { 120 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) 121 die("Cannot read ELF header: %s\n", strerror(errno)); 122 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) 123 die("No ELF magic\n"); 124 if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) 125 die("Not a %d bit executable\n", ELF_BITS); 126 if (ehdr.e_ident[EI_DATA] != ELF_ENDIAN) 127 die("ELF endian mismatch\n"); 128 if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) 129 die("Unknown ELF version\n"); 130 131 /* Convert the fields to native endian */ 132 ehdr.e_type = elf_half_to_cpu(ehdr.e_type); 133 ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine); 134 ehdr.e_version = elf_word_to_cpu(ehdr.e_version); 135 ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry); 136 ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff); 137 ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff); 138 ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags); 139 ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize); 140 ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize); 141 ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum); 142 ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize); 143 ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum); 144 ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx); 145 146 shnum = ehdr.e_shnum; 147 shstrndx = ehdr.e_shstrndx; 148 149 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) 150 die("Unsupported ELF header type\n"); 151 if (ehdr.e_machine != ELF_MACHINE) 152 die("Not for %s\n", ELF_MACHINE_NAME); 153 if (ehdr.e_version != EV_CURRENT) 154 die("Unknown ELF version\n"); 155 if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) 156 die("Bad Elf header size\n"); 157 if (ehdr.e_phentsize != sizeof(Elf_Phdr)) 158 die("Bad program header entry\n"); 159 if (ehdr.e_shentsize != sizeof(Elf_Shdr)) 160 die("Bad section header entry\n"); 161 162 if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) { 163 Elf_Shdr shdr; 164 165 if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) 166 die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno)); 167 168 if (fread(&shdr, sizeof(shdr), 1, fp) != 1) 169 die("Cannot read initial ELF section header: %s\n", strerror(errno)); 170 171 if (shnum == SHN_UNDEF) 172 shnum = elf_xword_to_cpu(shdr.sh_size); 173 174 if (shstrndx == SHN_XINDEX) 175 shstrndx = elf_word_to_cpu(shdr.sh_link); 176 } 177 178 if (shstrndx >= shnum) 179 die("String table index out of bounds\n"); 180 } 181 182 static void read_shdrs(FILE *fp) 183 { 184 Elf_Shdr shdr; 185 int i; 186 187 secs = calloc(shnum, sizeof(struct section)); 188 if (!secs) 189 die("Unable to allocate %ld section headers\n", shnum); 190 191 if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) 192 die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno)); 193 194 for (i = 0; i < shnum; i++) { 195 struct section *sec = &secs[i]; 196 197 if (fread(&shdr, sizeof(shdr), 1, fp) != 1) { 198 die("Cannot read ELF section headers %d/%ld: %s\n", 199 i, shnum, strerror(errno)); 200 } 201 202 sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name); 203 sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type); 204 sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags); 205 sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr); 206 sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset); 207 sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size); 208 sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link); 209 sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info); 210 sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign); 211 sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize); 212 213 if (sec->shdr.sh_link < shnum) 214 sec->link = &secs[sec->shdr.sh_link]; 215 } 216 217 } 218 219 static void read_relocs(FILE *fp) 220 { 221 int i, j; 222 223 for (i = 0; i < shnum; i++) { 224 struct section *sec = &secs[i]; 225 226 if (sec->shdr.sh_type != SHT_REL_TYPE) 227 continue; 228 229 sec->reltab = malloc(sec->shdr.sh_size); 230 if (!sec->reltab) 231 die("malloc of %" FMT " bytes for relocs failed\n", sec->shdr.sh_size); 232 233 if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) 234 die("Seek to %" FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno)); 235 236 if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size) 237 die("Cannot read symbol table: %s\n", strerror(errno)); 238 239 for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) { 240 Elf_Rel *rel = &sec->reltab[j]; 241 242 rel->r_offset = elf_addr_to_cpu(rel->r_offset); 243 rel->r_info = elf_xword_to_cpu(rel->r_info); 244 #if (SHT_REL_TYPE == SHT_RELA) 245 rel->r_addend = elf_xword_to_cpu(rel->r_addend); 246 #endif 247 } 248 } 249 } 250 251 static void add_reloc(struct relocs *r, uint32_t offset) 252 { 253 if (r->count == r->size) { 254 unsigned long newsize = r->size + 50000; 255 void *mem = realloc(r->offset, newsize * sizeof(r->offset[0])); 256 257 if (!mem) 258 die("realloc of %ld entries for relocs failed\n", newsize); 259 260 r->offset = mem; 261 r->size = newsize; 262 } 263 r->offset[r->count++] = offset; 264 } 265 266 static int do_reloc(struct section *sec, Elf_Rel *rel) 267 { 268 unsigned int r_type = ELF64_R_TYPE(rel->r_info); 269 ElfW(Addr) offset = rel->r_offset; 270 271 switch (r_type) { 272 case R_390_NONE: 273 case R_390_PC32: 274 case R_390_PC64: 275 case R_390_PC16DBL: 276 case R_390_PC32DBL: 277 case R_390_PLT32DBL: 278 case R_390_GOTENT: 279 case R_390_GOTPCDBL: 280 case R_390_GOTOFF64: 281 break; 282 case R_390_64: 283 add_reloc(&relocs64, offset); 284 break; 285 default: 286 die("Unsupported relocation type: %d\n", r_type); 287 break; 288 } 289 290 return 0; 291 } 292 293 static void walk_relocs(void) 294 { 295 int i; 296 297 /* Walk through the relocations */ 298 for (i = 0; i < shnum; i++) { 299 struct section *sec_applies; 300 int j; 301 struct section *sec = &secs[i]; 302 303 if (sec->shdr.sh_type != SHT_REL_TYPE) 304 continue; 305 306 sec_applies = &secs[sec->shdr.sh_info]; 307 if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) 308 continue; 309 310 for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) { 311 Elf_Rel *rel = &sec->reltab[j]; 312 313 do_reloc(sec, rel); 314 } 315 } 316 } 317 318 static int cmp_relocs(const void *va, const void *vb) 319 { 320 const uint32_t *a, *b; 321 322 a = va; b = vb; 323 return (*a == *b) ? 0 : (*a > *b) ? 1 : -1; 324 } 325 326 static void sort_relocs(struct relocs *r) 327 { 328 qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs); 329 } 330 331 static int print_reloc(uint32_t v) 332 { 333 return fprintf(stdout, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1; 334 } 335 336 static void emit_relocs(void) 337 { 338 int i; 339 340 walk_relocs(); 341 sort_relocs(&relocs64); 342 343 printf(".section \".vmlinux.relocs_64\",\"a\"\n"); 344 for (i = 0; i < relocs64.count; i++) 345 print_reloc(relocs64.offset[i]); 346 } 347 348 static void process(FILE *fp) 349 { 350 read_ehdr(fp); 351 read_shdrs(fp); 352 read_relocs(fp); 353 emit_relocs(); 354 } 355 356 static void usage(void) 357 { 358 die("relocs vmlinux\n"); 359 } 360 361 int main(int argc, char **argv) 362 { 363 unsigned char e_ident[EI_NIDENT]; 364 const char *fname; 365 FILE *fp; 366 367 fname = NULL; 368 369 if (argc != 2) 370 usage(); 371 372 fname = argv[1]; 373 374 fp = fopen(fname, "r"); 375 if (!fp) 376 die("Cannot open %s: %s\n", fname, strerror(errno)); 377 378 if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT) 379 die("Cannot read %s: %s", fname, strerror(errno)); 380 381 rewind(fp); 382 383 process(fp); 384 385 fclose(fp); 386 return 0; 387 } 388
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.