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 
elf16_to_cpu(uint16_t val)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 
elf32_to_cpu(uint32_t val)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 
elf64_to_cpu(uint64_t val)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 
die(char * fmt,...)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 
read_ehdr(FILE * fp)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 
read_shdrs(FILE * fp)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 
read_relocs(FILE * fp)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 
add_reloc(struct relocs * r,uint32_t offset)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 
do_reloc(struct section * sec,Elf_Rel * rel)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 
walk_relocs(void)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 
cmp_relocs(const void * va,const void * vb)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 
sort_relocs(struct relocs * r)326 static void sort_relocs(struct relocs *r)
327 {
328 	qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
329 }
330 
print_reloc(uint32_t v)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 
emit_relocs(void)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 
process(FILE * fp)348 static void process(FILE *fp)
349 {
350 	read_ehdr(fp);
351 	read_shdrs(fp);
352 	read_relocs(fp);
353 	emit_relocs();
354 }
355 
usage(void)356 static void usage(void)
357 {
358 	die("relocs vmlinux\n");
359 }
360 
main(int argc,char ** argv)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