155dc65b4SJosh Poimboeuf // SPDX-License-Identifier: GPL-2.0
255dc65b4SJosh Poimboeuf
355dc65b4SJosh Poimboeuf #include <stdio.h>
455dc65b4SJosh Poimboeuf #include <stdarg.h>
555dc65b4SJosh Poimboeuf #include <stdlib.h>
655dc65b4SJosh Poimboeuf #include <stdint.h>
755dc65b4SJosh Poimboeuf #include <inttypes.h>
855dc65b4SJosh Poimboeuf #include <string.h>
955dc65b4SJosh Poimboeuf #include <errno.h>
1055dc65b4SJosh Poimboeuf #include <unistd.h>
1155dc65b4SJosh Poimboeuf #include <elf.h>
1255dc65b4SJosh Poimboeuf #include <byteswap.h>
1355dc65b4SJosh Poimboeuf #define USE_BSD
1455dc65b4SJosh Poimboeuf #include <endian.h>
1555dc65b4SJosh Poimboeuf
1655dc65b4SJosh Poimboeuf #define ELF_BITS 64
1755dc65b4SJosh Poimboeuf
1855dc65b4SJosh Poimboeuf #define ELF_MACHINE EM_S390
1955dc65b4SJosh Poimboeuf #define ELF_MACHINE_NAME "IBM S/390"
2055dc65b4SJosh Poimboeuf #define SHT_REL_TYPE SHT_RELA
2155dc65b4SJosh Poimboeuf #define Elf_Rel Elf64_Rela
2255dc65b4SJosh Poimboeuf
2355dc65b4SJosh Poimboeuf #define ELF_CLASS ELFCLASS64
2455dc65b4SJosh Poimboeuf #define ELF_ENDIAN ELFDATA2MSB
2555dc65b4SJosh Poimboeuf #define ELF_R_SYM(val) ELF64_R_SYM(val)
2655dc65b4SJosh Poimboeuf #define ELF_R_TYPE(val) ELF64_R_TYPE(val)
2755dc65b4SJosh Poimboeuf #define ELF_ST_TYPE(o) ELF64_ST_TYPE(o)
2855dc65b4SJosh Poimboeuf #define ELF_ST_BIND(o) ELF64_ST_BIND(o)
2955dc65b4SJosh Poimboeuf #define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o)
3055dc65b4SJosh Poimboeuf
3155dc65b4SJosh Poimboeuf #define ElfW(type) _ElfW(ELF_BITS, type)
3255dc65b4SJosh Poimboeuf #define _ElfW(bits, type) __ElfW(bits, type)
3355dc65b4SJosh Poimboeuf #define __ElfW(bits, type) Elf##bits##_##type
3455dc65b4SJosh Poimboeuf
3555dc65b4SJosh Poimboeuf #define Elf_Addr ElfW(Addr)
3655dc65b4SJosh Poimboeuf #define Elf_Ehdr ElfW(Ehdr)
3755dc65b4SJosh Poimboeuf #define Elf_Phdr ElfW(Phdr)
3855dc65b4SJosh Poimboeuf #define Elf_Shdr ElfW(Shdr)
3955dc65b4SJosh Poimboeuf #define Elf_Sym ElfW(Sym)
4055dc65b4SJosh Poimboeuf
4155dc65b4SJosh Poimboeuf static Elf_Ehdr ehdr;
4255dc65b4SJosh Poimboeuf static unsigned long shnum;
4355dc65b4SJosh Poimboeuf static unsigned int shstrndx;
4455dc65b4SJosh Poimboeuf
4555dc65b4SJosh Poimboeuf struct relocs {
4655dc65b4SJosh Poimboeuf uint32_t *offset;
4755dc65b4SJosh Poimboeuf unsigned long count;
4855dc65b4SJosh Poimboeuf unsigned long size;
4955dc65b4SJosh Poimboeuf };
5055dc65b4SJosh Poimboeuf
5155dc65b4SJosh Poimboeuf static struct relocs relocs64;
5255dc65b4SJosh Poimboeuf #define FMT PRIu64
5355dc65b4SJosh Poimboeuf
5455dc65b4SJosh Poimboeuf struct section {
5555dc65b4SJosh Poimboeuf Elf_Shdr shdr;
5655dc65b4SJosh Poimboeuf struct section *link;
5755dc65b4SJosh Poimboeuf Elf_Rel *reltab;
5855dc65b4SJosh Poimboeuf };
5955dc65b4SJosh Poimboeuf
6055dc65b4SJosh Poimboeuf static struct section *secs;
6155dc65b4SJosh Poimboeuf
6255dc65b4SJosh Poimboeuf #if BYTE_ORDER == LITTLE_ENDIAN
6355dc65b4SJosh Poimboeuf #define le16_to_cpu(val) (val)
6455dc65b4SJosh Poimboeuf #define le32_to_cpu(val) (val)
6555dc65b4SJosh Poimboeuf #define le64_to_cpu(val) (val)
6655dc65b4SJosh Poimboeuf #define be16_to_cpu(val) bswap_16(val)
6755dc65b4SJosh Poimboeuf #define be32_to_cpu(val) bswap_32(val)
6855dc65b4SJosh Poimboeuf #define be64_to_cpu(val) bswap_64(val)
6955dc65b4SJosh Poimboeuf #endif
7055dc65b4SJosh Poimboeuf
7155dc65b4SJosh Poimboeuf #if BYTE_ORDER == BIG_ENDIAN
7255dc65b4SJosh Poimboeuf #define le16_to_cpu(val) bswap_16(val)
7355dc65b4SJosh Poimboeuf #define le32_to_cpu(val) bswap_32(val)
7455dc65b4SJosh Poimboeuf #define le64_to_cpu(val) bswap_64(val)
7555dc65b4SJosh Poimboeuf #define be16_to_cpu(val) (val)
7655dc65b4SJosh Poimboeuf #define be32_to_cpu(val) (val)
7755dc65b4SJosh Poimboeuf #define be64_to_cpu(val) (val)
7855dc65b4SJosh Poimboeuf #endif
7955dc65b4SJosh Poimboeuf
elf16_to_cpu(uint16_t val)8055dc65b4SJosh Poimboeuf static uint16_t elf16_to_cpu(uint16_t val)
8155dc65b4SJosh Poimboeuf {
8255dc65b4SJosh Poimboeuf if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
8355dc65b4SJosh Poimboeuf return le16_to_cpu(val);
8455dc65b4SJosh Poimboeuf else
8555dc65b4SJosh Poimboeuf return be16_to_cpu(val);
8655dc65b4SJosh Poimboeuf }
8755dc65b4SJosh Poimboeuf
elf32_to_cpu(uint32_t val)8855dc65b4SJosh Poimboeuf static uint32_t elf32_to_cpu(uint32_t val)
8955dc65b4SJosh Poimboeuf {
9055dc65b4SJosh Poimboeuf if (ehdr.e_ident[EI_DATA] == ELFDATA2LSB)
9155dc65b4SJosh Poimboeuf return le32_to_cpu(val);
9255dc65b4SJosh Poimboeuf else
9355dc65b4SJosh Poimboeuf return be32_to_cpu(val);
9455dc65b4SJosh Poimboeuf }
9555dc65b4SJosh Poimboeuf
9655dc65b4SJosh Poimboeuf #define elf_half_to_cpu(x) elf16_to_cpu(x)
9755dc65b4SJosh Poimboeuf #define elf_word_to_cpu(x) elf32_to_cpu(x)
9855dc65b4SJosh Poimboeuf
elf64_to_cpu(uint64_t val)9955dc65b4SJosh Poimboeuf static uint64_t elf64_to_cpu(uint64_t val)
10055dc65b4SJosh Poimboeuf {
10155dc65b4SJosh Poimboeuf return be64_to_cpu(val);
10255dc65b4SJosh Poimboeuf }
10355dc65b4SJosh Poimboeuf
10455dc65b4SJosh Poimboeuf #define elf_addr_to_cpu(x) elf64_to_cpu(x)
10555dc65b4SJosh Poimboeuf #define elf_off_to_cpu(x) elf64_to_cpu(x)
10655dc65b4SJosh Poimboeuf #define elf_xword_to_cpu(x) elf64_to_cpu(x)
10755dc65b4SJosh Poimboeuf
die(char * fmt,...)10855dc65b4SJosh Poimboeuf static void die(char *fmt, ...)
10955dc65b4SJosh Poimboeuf {
11055dc65b4SJosh Poimboeuf va_list ap;
11155dc65b4SJosh Poimboeuf
11255dc65b4SJosh Poimboeuf va_start(ap, fmt);
11355dc65b4SJosh Poimboeuf vfprintf(stderr, fmt, ap);
11455dc65b4SJosh Poimboeuf va_end(ap);
11555dc65b4SJosh Poimboeuf exit(1);
11655dc65b4SJosh Poimboeuf }
11755dc65b4SJosh Poimboeuf
read_ehdr(FILE * fp)11855dc65b4SJosh Poimboeuf static void read_ehdr(FILE *fp)
11955dc65b4SJosh Poimboeuf {
12055dc65b4SJosh Poimboeuf if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
12155dc65b4SJosh Poimboeuf die("Cannot read ELF header: %s\n", strerror(errno));
12255dc65b4SJosh Poimboeuf if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0)
12355dc65b4SJosh Poimboeuf die("No ELF magic\n");
12455dc65b4SJosh Poimboeuf if (ehdr.e_ident[EI_CLASS] != ELF_CLASS)
12555dc65b4SJosh Poimboeuf die("Not a %d bit executable\n", ELF_BITS);
12655dc65b4SJosh Poimboeuf if (ehdr.e_ident[EI_DATA] != ELF_ENDIAN)
12755dc65b4SJosh Poimboeuf die("ELF endian mismatch\n");
12855dc65b4SJosh Poimboeuf if (ehdr.e_ident[EI_VERSION] != EV_CURRENT)
12955dc65b4SJosh Poimboeuf die("Unknown ELF version\n");
13055dc65b4SJosh Poimboeuf
13155dc65b4SJosh Poimboeuf /* Convert the fields to native endian */
13255dc65b4SJosh Poimboeuf ehdr.e_type = elf_half_to_cpu(ehdr.e_type);
13355dc65b4SJosh Poimboeuf ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine);
13455dc65b4SJosh Poimboeuf ehdr.e_version = elf_word_to_cpu(ehdr.e_version);
13555dc65b4SJosh Poimboeuf ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry);
13655dc65b4SJosh Poimboeuf ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff);
13755dc65b4SJosh Poimboeuf ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff);
13855dc65b4SJosh Poimboeuf ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags);
13955dc65b4SJosh Poimboeuf ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize);
14055dc65b4SJosh Poimboeuf ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
14155dc65b4SJosh Poimboeuf ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum);
14255dc65b4SJosh Poimboeuf ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
14355dc65b4SJosh Poimboeuf ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum);
14455dc65b4SJosh Poimboeuf ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx);
14555dc65b4SJosh Poimboeuf
14655dc65b4SJosh Poimboeuf shnum = ehdr.e_shnum;
14755dc65b4SJosh Poimboeuf shstrndx = ehdr.e_shstrndx;
14855dc65b4SJosh Poimboeuf
14955dc65b4SJosh Poimboeuf if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN))
15055dc65b4SJosh Poimboeuf die("Unsupported ELF header type\n");
15155dc65b4SJosh Poimboeuf if (ehdr.e_machine != ELF_MACHINE)
15255dc65b4SJosh Poimboeuf die("Not for %s\n", ELF_MACHINE_NAME);
15355dc65b4SJosh Poimboeuf if (ehdr.e_version != EV_CURRENT)
15455dc65b4SJosh Poimboeuf die("Unknown ELF version\n");
15555dc65b4SJosh Poimboeuf if (ehdr.e_ehsize != sizeof(Elf_Ehdr))
15655dc65b4SJosh Poimboeuf die("Bad Elf header size\n");
15755dc65b4SJosh Poimboeuf if (ehdr.e_phentsize != sizeof(Elf_Phdr))
15855dc65b4SJosh Poimboeuf die("Bad program header entry\n");
15955dc65b4SJosh Poimboeuf if (ehdr.e_shentsize != sizeof(Elf_Shdr))
16055dc65b4SJosh Poimboeuf die("Bad section header entry\n");
16155dc65b4SJosh Poimboeuf
16255dc65b4SJosh Poimboeuf if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) {
16355dc65b4SJosh Poimboeuf Elf_Shdr shdr;
16455dc65b4SJosh Poimboeuf
16555dc65b4SJosh Poimboeuf if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
16655dc65b4SJosh Poimboeuf die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno));
16755dc65b4SJosh Poimboeuf
16855dc65b4SJosh Poimboeuf if (fread(&shdr, sizeof(shdr), 1, fp) != 1)
16955dc65b4SJosh Poimboeuf die("Cannot read initial ELF section header: %s\n", strerror(errno));
17055dc65b4SJosh Poimboeuf
17155dc65b4SJosh Poimboeuf if (shnum == SHN_UNDEF)
17255dc65b4SJosh Poimboeuf shnum = elf_xword_to_cpu(shdr.sh_size);
17355dc65b4SJosh Poimboeuf
17455dc65b4SJosh Poimboeuf if (shstrndx == SHN_XINDEX)
17555dc65b4SJosh Poimboeuf shstrndx = elf_word_to_cpu(shdr.sh_link);
17655dc65b4SJosh Poimboeuf }
17755dc65b4SJosh Poimboeuf
17855dc65b4SJosh Poimboeuf if (shstrndx >= shnum)
17955dc65b4SJosh Poimboeuf die("String table index out of bounds\n");
18055dc65b4SJosh Poimboeuf }
18155dc65b4SJosh Poimboeuf
read_shdrs(FILE * fp)18255dc65b4SJosh Poimboeuf static void read_shdrs(FILE *fp)
18355dc65b4SJosh Poimboeuf {
18455dc65b4SJosh Poimboeuf Elf_Shdr shdr;
18555dc65b4SJosh Poimboeuf int i;
18655dc65b4SJosh Poimboeuf
18755dc65b4SJosh Poimboeuf secs = calloc(shnum, sizeof(struct section));
18855dc65b4SJosh Poimboeuf if (!secs)
18955dc65b4SJosh Poimboeuf die("Unable to allocate %ld section headers\n", shnum);
19055dc65b4SJosh Poimboeuf
19155dc65b4SJosh Poimboeuf if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
19255dc65b4SJosh Poimboeuf die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno));
19355dc65b4SJosh Poimboeuf
19455dc65b4SJosh Poimboeuf for (i = 0; i < shnum; i++) {
19555dc65b4SJosh Poimboeuf struct section *sec = &secs[i];
19655dc65b4SJosh Poimboeuf
19755dc65b4SJosh Poimboeuf if (fread(&shdr, sizeof(shdr), 1, fp) != 1) {
19855dc65b4SJosh Poimboeuf die("Cannot read ELF section headers %d/%ld: %s\n",
19955dc65b4SJosh Poimboeuf i, shnum, strerror(errno));
20055dc65b4SJosh Poimboeuf }
20155dc65b4SJosh Poimboeuf
20255dc65b4SJosh Poimboeuf sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name);
20355dc65b4SJosh Poimboeuf sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type);
20455dc65b4SJosh Poimboeuf sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags);
20555dc65b4SJosh Poimboeuf sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr);
20655dc65b4SJosh Poimboeuf sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset);
20755dc65b4SJosh Poimboeuf sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size);
20855dc65b4SJosh Poimboeuf sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link);
20955dc65b4SJosh Poimboeuf sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info);
21055dc65b4SJosh Poimboeuf sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
21155dc65b4SJosh Poimboeuf sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize);
21255dc65b4SJosh Poimboeuf
21355dc65b4SJosh Poimboeuf if (sec->shdr.sh_link < shnum)
21455dc65b4SJosh Poimboeuf sec->link = &secs[sec->shdr.sh_link];
21555dc65b4SJosh Poimboeuf }
21655dc65b4SJosh Poimboeuf
21755dc65b4SJosh Poimboeuf }
21855dc65b4SJosh Poimboeuf
read_relocs(FILE * fp)21955dc65b4SJosh Poimboeuf static void read_relocs(FILE *fp)
22055dc65b4SJosh Poimboeuf {
22155dc65b4SJosh Poimboeuf int i, j;
22255dc65b4SJosh Poimboeuf
22355dc65b4SJosh Poimboeuf for (i = 0; i < shnum; i++) {
22455dc65b4SJosh Poimboeuf struct section *sec = &secs[i];
22555dc65b4SJosh Poimboeuf
22655dc65b4SJosh Poimboeuf if (sec->shdr.sh_type != SHT_REL_TYPE)
22755dc65b4SJosh Poimboeuf continue;
22855dc65b4SJosh Poimboeuf
22955dc65b4SJosh Poimboeuf sec->reltab = malloc(sec->shdr.sh_size);
23055dc65b4SJosh Poimboeuf if (!sec->reltab)
23155dc65b4SJosh Poimboeuf die("malloc of %" FMT " bytes for relocs failed\n", sec->shdr.sh_size);
23255dc65b4SJosh Poimboeuf
23355dc65b4SJosh Poimboeuf if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0)
23455dc65b4SJosh Poimboeuf die("Seek to %" FMT " failed: %s\n", sec->shdr.sh_offset, strerror(errno));
23555dc65b4SJosh Poimboeuf
23655dc65b4SJosh Poimboeuf if (fread(sec->reltab, 1, sec->shdr.sh_size, fp) != sec->shdr.sh_size)
23755dc65b4SJosh Poimboeuf die("Cannot read symbol table: %s\n", strerror(errno));
23855dc65b4SJosh Poimboeuf
23955dc65b4SJosh Poimboeuf for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) {
24055dc65b4SJosh Poimboeuf Elf_Rel *rel = &sec->reltab[j];
24155dc65b4SJosh Poimboeuf
24255dc65b4SJosh Poimboeuf rel->r_offset = elf_addr_to_cpu(rel->r_offset);
24355dc65b4SJosh Poimboeuf rel->r_info = elf_xword_to_cpu(rel->r_info);
24455dc65b4SJosh Poimboeuf #if (SHT_REL_TYPE == SHT_RELA)
24555dc65b4SJosh Poimboeuf rel->r_addend = elf_xword_to_cpu(rel->r_addend);
24655dc65b4SJosh Poimboeuf #endif
24755dc65b4SJosh Poimboeuf }
24855dc65b4SJosh Poimboeuf }
24955dc65b4SJosh Poimboeuf }
25055dc65b4SJosh Poimboeuf
add_reloc(struct relocs * r,uint32_t offset)25155dc65b4SJosh Poimboeuf static void add_reloc(struct relocs *r, uint32_t offset)
25255dc65b4SJosh Poimboeuf {
25355dc65b4SJosh Poimboeuf if (r->count == r->size) {
25455dc65b4SJosh Poimboeuf unsigned long newsize = r->size + 50000;
25555dc65b4SJosh Poimboeuf void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
25655dc65b4SJosh Poimboeuf
25755dc65b4SJosh Poimboeuf if (!mem)
25855dc65b4SJosh Poimboeuf die("realloc of %ld entries for relocs failed\n", newsize);
25955dc65b4SJosh Poimboeuf
26055dc65b4SJosh Poimboeuf r->offset = mem;
26155dc65b4SJosh Poimboeuf r->size = newsize;
26255dc65b4SJosh Poimboeuf }
26355dc65b4SJosh Poimboeuf r->offset[r->count++] = offset;
26455dc65b4SJosh Poimboeuf }
26555dc65b4SJosh Poimboeuf
do_reloc(struct section * sec,Elf_Rel * rel)26655dc65b4SJosh Poimboeuf static int do_reloc(struct section *sec, Elf_Rel *rel)
26755dc65b4SJosh Poimboeuf {
26855dc65b4SJosh Poimboeuf unsigned int r_type = ELF64_R_TYPE(rel->r_info);
26955dc65b4SJosh Poimboeuf ElfW(Addr) offset = rel->r_offset;
27055dc65b4SJosh Poimboeuf
27155dc65b4SJosh Poimboeuf switch (r_type) {
27255dc65b4SJosh Poimboeuf case R_390_NONE:
27355dc65b4SJosh Poimboeuf case R_390_PC32:
27455dc65b4SJosh Poimboeuf case R_390_PC64:
27555dc65b4SJosh Poimboeuf case R_390_PC16DBL:
27655dc65b4SJosh Poimboeuf case R_390_PC32DBL:
27755dc65b4SJosh Poimboeuf case R_390_PLT32DBL:
27855dc65b4SJosh Poimboeuf case R_390_GOTENT:
279fa9e3139SSumanth Korikkar case R_390_GOTPCDBL:
280fa9e3139SSumanth Korikkar case R_390_GOTOFF64:
28155dc65b4SJosh Poimboeuf break;
28255dc65b4SJosh Poimboeuf case R_390_64:
283*1642285eSAlexander Gordeev add_reloc(&relocs64, offset);
28455dc65b4SJosh Poimboeuf break;
28555dc65b4SJosh Poimboeuf default:
28655dc65b4SJosh Poimboeuf die("Unsupported relocation type: %d\n", r_type);
28755dc65b4SJosh Poimboeuf break;
28855dc65b4SJosh Poimboeuf }
28955dc65b4SJosh Poimboeuf
29055dc65b4SJosh Poimboeuf return 0;
29155dc65b4SJosh Poimboeuf }
29255dc65b4SJosh Poimboeuf
walk_relocs(void)29355dc65b4SJosh Poimboeuf static void walk_relocs(void)
29455dc65b4SJosh Poimboeuf {
29555dc65b4SJosh Poimboeuf int i;
29655dc65b4SJosh Poimboeuf
29755dc65b4SJosh Poimboeuf /* Walk through the relocations */
29855dc65b4SJosh Poimboeuf for (i = 0; i < shnum; i++) {
29955dc65b4SJosh Poimboeuf struct section *sec_applies;
30055dc65b4SJosh Poimboeuf int j;
30155dc65b4SJosh Poimboeuf struct section *sec = &secs[i];
30255dc65b4SJosh Poimboeuf
30355dc65b4SJosh Poimboeuf if (sec->shdr.sh_type != SHT_REL_TYPE)
30455dc65b4SJosh Poimboeuf continue;
30555dc65b4SJosh Poimboeuf
30655dc65b4SJosh Poimboeuf sec_applies = &secs[sec->shdr.sh_info];
30755dc65b4SJosh Poimboeuf if (!(sec_applies->shdr.sh_flags & SHF_ALLOC))
30855dc65b4SJosh Poimboeuf continue;
30955dc65b4SJosh Poimboeuf
31055dc65b4SJosh Poimboeuf for (j = 0; j < sec->shdr.sh_size / sizeof(Elf_Rel); j++) {
31155dc65b4SJosh Poimboeuf Elf_Rel *rel = &sec->reltab[j];
31255dc65b4SJosh Poimboeuf
31355dc65b4SJosh Poimboeuf do_reloc(sec, rel);
31455dc65b4SJosh Poimboeuf }
31555dc65b4SJosh Poimboeuf }
31655dc65b4SJosh Poimboeuf }
31755dc65b4SJosh Poimboeuf
cmp_relocs(const void * va,const void * vb)31855dc65b4SJosh Poimboeuf static int cmp_relocs(const void *va, const void *vb)
31955dc65b4SJosh Poimboeuf {
32055dc65b4SJosh Poimboeuf const uint32_t *a, *b;
32155dc65b4SJosh Poimboeuf
32255dc65b4SJosh Poimboeuf a = va; b = vb;
32355dc65b4SJosh Poimboeuf return (*a == *b) ? 0 : (*a > *b) ? 1 : -1;
32455dc65b4SJosh Poimboeuf }
32555dc65b4SJosh Poimboeuf
sort_relocs(struct relocs * r)32655dc65b4SJosh Poimboeuf static void sort_relocs(struct relocs *r)
32755dc65b4SJosh Poimboeuf {
32855dc65b4SJosh Poimboeuf qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
32955dc65b4SJosh Poimboeuf }
33055dc65b4SJosh Poimboeuf
print_reloc(uint32_t v)33155dc65b4SJosh Poimboeuf static int print_reloc(uint32_t v)
33255dc65b4SJosh Poimboeuf {
33355dc65b4SJosh Poimboeuf return fprintf(stdout, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
33455dc65b4SJosh Poimboeuf }
33555dc65b4SJosh Poimboeuf
emit_relocs(void)33655dc65b4SJosh Poimboeuf static void emit_relocs(void)
33755dc65b4SJosh Poimboeuf {
33855dc65b4SJosh Poimboeuf int i;
33955dc65b4SJosh Poimboeuf
34055dc65b4SJosh Poimboeuf walk_relocs();
34155dc65b4SJosh Poimboeuf sort_relocs(&relocs64);
34255dc65b4SJosh Poimboeuf
34355dc65b4SJosh Poimboeuf printf(".section \".vmlinux.relocs_64\",\"a\"\n");
34455dc65b4SJosh Poimboeuf for (i = 0; i < relocs64.count; i++)
34555dc65b4SJosh Poimboeuf print_reloc(relocs64.offset[i]);
34655dc65b4SJosh Poimboeuf }
34755dc65b4SJosh Poimboeuf
process(FILE * fp)34855dc65b4SJosh Poimboeuf static void process(FILE *fp)
34955dc65b4SJosh Poimboeuf {
35055dc65b4SJosh Poimboeuf read_ehdr(fp);
35155dc65b4SJosh Poimboeuf read_shdrs(fp);
35255dc65b4SJosh Poimboeuf read_relocs(fp);
35355dc65b4SJosh Poimboeuf emit_relocs();
35455dc65b4SJosh Poimboeuf }
35555dc65b4SJosh Poimboeuf
usage(void)35655dc65b4SJosh Poimboeuf static void usage(void)
35755dc65b4SJosh Poimboeuf {
35855dc65b4SJosh Poimboeuf die("relocs vmlinux\n");
35955dc65b4SJosh Poimboeuf }
36055dc65b4SJosh Poimboeuf
main(int argc,char ** argv)36155dc65b4SJosh Poimboeuf int main(int argc, char **argv)
36255dc65b4SJosh Poimboeuf {
36355dc65b4SJosh Poimboeuf unsigned char e_ident[EI_NIDENT];
36455dc65b4SJosh Poimboeuf const char *fname;
36555dc65b4SJosh Poimboeuf FILE *fp;
36655dc65b4SJosh Poimboeuf
36755dc65b4SJosh Poimboeuf fname = NULL;
36855dc65b4SJosh Poimboeuf
36955dc65b4SJosh Poimboeuf if (argc != 2)
37055dc65b4SJosh Poimboeuf usage();
37155dc65b4SJosh Poimboeuf
37255dc65b4SJosh Poimboeuf fname = argv[1];
37355dc65b4SJosh Poimboeuf
37455dc65b4SJosh Poimboeuf fp = fopen(fname, "r");
37555dc65b4SJosh Poimboeuf if (!fp)
37655dc65b4SJosh Poimboeuf die("Cannot open %s: %s\n", fname, strerror(errno));
37755dc65b4SJosh Poimboeuf
37855dc65b4SJosh Poimboeuf if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT)
37955dc65b4SJosh Poimboeuf die("Cannot read %s: %s", fname, strerror(errno));
38055dc65b4SJosh Poimboeuf
38155dc65b4SJosh Poimboeuf rewind(fp);
38255dc65b4SJosh Poimboeuf
38355dc65b4SJosh Poimboeuf process(fp);
38455dc65b4SJosh Poimboeuf
38555dc65b4SJosh Poimboeuf fclose(fp);
38655dc65b4SJosh Poimboeuf return 0;
38755dc65b4SJosh Poimboeuf }
388