1968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <stdio.h>
2968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <stdarg.h>
3968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <stdlib.h>
4968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <stdint.h>
5968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <string.h>
6968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <errno.h>
7968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <unistd.h>
8968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <elf.h>
9968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <byteswap.h>
10968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define USE_BSD
11968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#include <endian.h>
12873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin#include <regex.h>
1355f9709cd07c9d33e30b575ee1b3bfd0aeaa3760Matt Fleming#include <tools/le_byteshift.h>
14873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin
15873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvinstatic void die(char *fmt, ...);
16968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
17ca820181fc187af316a18b2700582663662c4012Robert P. J. Day#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
18968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic Elf32_Ehdr ehdr;
19968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic unsigned long reloc_count, reloc_idx;
20968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic unsigned long *relocs;
216520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic unsigned long reloc16_count, reloc16_idx;
226520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic unsigned long *relocs16;
23968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
24908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvinstruct section {
25908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	Elf32_Shdr     shdr;
26908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	struct section *link;
27908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	Elf32_Sym      *symtab;
28908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	Elf32_Rel      *reltab;
29908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	char           *strtab;
30908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin};
31908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvinstatic struct section *secs;
32908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin
336520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinenum symtype {
346520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	S_ABS,
356520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	S_REL,
366520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	S_SEG,
376520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	S_LIN,
386520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	S_NSYMTYPES
396520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin};
406520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
416520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic const char * const sym_regex_kernel[S_NSYMTYPES] = {
426a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal/*
436a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal * Following symbols have been audited. There values are constant and do
446a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal * not change if bzImage is loaded at a different physical address than
456a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal * the address for which it has been compiled. Don't warn user about
466a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal * absolute relocations present w.r.t these symbols.
476a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal */
486520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	[S_ABS] =
49873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin	"^(xen_irq_disable_direct_reloc$|"
50873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin	"xen_save_fl_direct_reloc$|"
51873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin	"VDSO|"
526520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	"__crc_)",
536a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
54873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin/*
55873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin * These symbols are known to be relative, even if the linker marks them
56873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin * as absolute (typically defined outside any section in the linker script.)
57873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin */
586520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	[S_REL] =
59a3e854d95a76862cd37937e0b0438f540536771aH. Peter Anvin	"^(__init_(begin|end)|"
60a3e854d95a76862cd37937e0b0438f540536771aH. Peter Anvin	"__x86_cpu_dev_(start|end)|"
61a3e854d95a76862cd37937e0b0438f540536771aH. Peter Anvin	"(__parainstructions|__alt_instructions)(|_end)|"
62a3e854d95a76862cd37937e0b0438f540536771aH. Peter Anvin	"(__iommu_table|__apicdrivers|__smp_locks)(|_end)|"
633c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|end)_pci_.*|"
643c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|end)_builtin_fw|"
653c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|stop)___ksymtab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
663c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|stop)___kcrctab(|_gpl|_unused|_unused_gpl|_gpl_future)|"
673c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|stop)___param|"
683c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|stop)___modver|"
693c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|stop)___bug_table|"
703c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__tracedata_(start|end)|"
713c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__(start|stop)_notes|"
723c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__end_rodata|"
733c47c685100285be39ff7e347f762480b448b956H. Peter Anvin	"__initramfs_start|"
74c51ac8ac9a82d4883c9b62247cca98195da8cd63H. Peter Anvin	"(jiffies|jiffies_64)|"
75a3e854d95a76862cd37937e0b0438f540536771aH. Peter Anvin	"_end)$"
766520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin};
776520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
786520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
796520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic const char * const sym_regex_realmode[S_NSYMTYPES] = {
806520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin/*
816520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin * These are 16-bit segment symbols when compiling 16-bit code.
826520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin */
836520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	[S_SEG] =
846520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	"^real_mode_seg$",
856520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
866520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin/*
876520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin * These are offsets belonging to segments, as opposed to linear addresses,
886520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin * when compiling 16-bit code.
896520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin */
906520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	[S_LIN] =
916520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	"^pa_",
926520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin};
936520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
946520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic const char * const *sym_regex;
956520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
966520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic regex_t sym_regex_c[S_NSYMTYPES];
976520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic int is_reloc(enum symtype type, const char *sym_name)
986a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal{
996520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	return sym_regex[type] &&
1006520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		!regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
101873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin}
1026a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
1036520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic void regex_init(int use_real_mode)
104873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin{
105873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin        char errbuf[128];
106873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin        int err;
1076520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	int i;
108873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin
1096520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	if (use_real_mode)
1106520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		sym_regex = sym_regex_realmode;
1116520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	else
1126520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		sym_regex = sym_regex_kernel;
1136520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
1146520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	for (i = 0; i < S_NSYMTYPES; i++) {
1156520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		if (!sym_regex[i])
1166520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			continue;
1176520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
1186520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		err = regcomp(&sym_regex_c[i], sym_regex[i],
1196520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			      REG_EXTENDED|REG_NOSUB);
1206520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
1216520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		if (err) {
1226520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf);
1236520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			die("%s", errbuf);
1246520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		}
125873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin        }
1266a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal}
1276a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
128968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void die(char *fmt, ...)
129968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
130968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	va_list ap;
131968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	va_start(ap, fmt);
132968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	vfprintf(stderr, fmt, ap);
133968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	va_end(ap);
134968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	exit(1);
135968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
136968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
137968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic const char *sym_type(unsigned type)
138968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
139968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	static const char *type_name[] = {
140968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define SYM_TYPE(X) [X] = #X
141968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_TYPE(STT_NOTYPE),
142968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_TYPE(STT_OBJECT),
143968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_TYPE(STT_FUNC),
144968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_TYPE(STT_SECTION),
145968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_TYPE(STT_FILE),
146968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_TYPE(STT_COMMON),
147968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_TYPE(STT_TLS),
148968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#undef SYM_TYPE
149968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	};
150968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *name = "unknown sym type name";
151ca820181fc187af316a18b2700582663662c4012Robert P. J. Day	if (type < ARRAY_SIZE(type_name)) {
152968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		name = type_name[type];
153968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
154968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return name;
155968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
156968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
157968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic const char *sym_bind(unsigned bind)
158968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
159968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	static const char *bind_name[] = {
160968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define SYM_BIND(X) [X] = #X
161968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_BIND(STB_LOCAL),
162968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_BIND(STB_GLOBAL),
163968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_BIND(STB_WEAK),
164968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#undef SYM_BIND
165968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	};
166968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *name = "unknown sym bind name";
167ca820181fc187af316a18b2700582663662c4012Robert P. J. Day	if (bind < ARRAY_SIZE(bind_name)) {
168968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		name = bind_name[bind];
169968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
170968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return name;
171968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
172968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
173968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic const char *sym_visibility(unsigned visibility)
174968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
175968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	static const char *visibility_name[] = {
176968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define SYM_VISIBILITY(X) [X] = #X
177968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_VISIBILITY(STV_DEFAULT),
178968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_VISIBILITY(STV_INTERNAL),
179968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_VISIBILITY(STV_HIDDEN),
180968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		SYM_VISIBILITY(STV_PROTECTED),
181968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#undef SYM_VISIBILITY
182968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	};
183968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *name = "unknown sym visibility name";
184ca820181fc187af316a18b2700582663662c4012Robert P. J. Day	if (visibility < ARRAY_SIZE(visibility_name)) {
185968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		name = visibility_name[visibility];
186968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
187968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return name;
188968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
189968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
190968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic const char *rel_type(unsigned type)
191968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
192968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	static const char *type_name[] = {
193968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define REL_TYPE(X) [X] = #X
194968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_NONE),
195968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_32),
196968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_PC32),
197968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_GOT32),
198968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_PLT32),
199968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_COPY),
200968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_GLOB_DAT),
201968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_JMP_SLOT),
202968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_RELATIVE),
203968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_GOTOFF),
204968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		REL_TYPE(R_386_GOTPC),
2056520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		REL_TYPE(R_386_8),
2066520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		REL_TYPE(R_386_PC8),
2076520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		REL_TYPE(R_386_16),
2086520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		REL_TYPE(R_386_PC16),
209968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#undef REL_TYPE
210968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	};
211968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *name = "unknown type rel type name";
212873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin	if (type < ARRAY_SIZE(type_name) && type_name[type]) {
213968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		name = type_name[type];
214968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
215968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return name;
216968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
217968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
218968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic const char *sec_name(unsigned shndx)
219968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
220968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *sec_strtab;
221968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *name;
222908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	sec_strtab = secs[ehdr.e_shstrndx].strtab;
223968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	name = "<noname>";
224968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (shndx < ehdr.e_shnum) {
225908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		name = sec_strtab + secs[shndx].shdr.sh_name;
226968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
227968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	else if (shndx == SHN_ABS) {
228968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		name = "ABSOLUTE";
229968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
230968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	else if (shndx == SHN_COMMON) {
231968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		name = "COMMON";
232968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
233968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return name;
234968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
235968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
236968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
237968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
238968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *name;
239968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	name = "<noname>";
240968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (sym->st_name) {
241968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		name = sym_strtab + sym->st_name;
242968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
243968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	else {
2446520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		name = sec_name(sym->st_shndx);
245968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
246968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return name;
247968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
248968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
249968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
250968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
25113da9e200fe4740b02cd51e07ab454627e228920Linus Torvalds#if BYTE_ORDER == LITTLE_ENDIAN
252968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define le16_to_cpu(val) (val)
253968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define le32_to_cpu(val) (val)
254968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#endif
25513da9e200fe4740b02cd51e07ab454627e228920Linus Torvalds#if BYTE_ORDER == BIG_ENDIAN
256968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define le16_to_cpu(val) bswap_16(val)
257968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#define le32_to_cpu(val) bswap_32(val)
258968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman#endif
259968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
260968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic uint16_t elf16_to_cpu(uint16_t val)
261968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
262968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return le16_to_cpu(val);
263968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
264968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
265968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic uint32_t elf32_to_cpu(uint32_t val)
266968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
267968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return le32_to_cpu(val);
268968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
269968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
270968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void read_ehdr(FILE *fp)
271968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
272968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
273968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Cannot read ELF header: %s\n",
274968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			strerror(errno));
275968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
2768bd1796dedd50abd7553afbe6113bd97cc88390fCyrill Gorcunov	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
277968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("No ELF magic\n");
278968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
279968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
280968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Not a 32 bit executable\n");
281968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
282968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
283968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Not a LSB ELF executable\n");
284968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
285968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
286968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Unknown ELF version\n");
287968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
288968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	/* Convert the fields to native endian */
289968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_type      = elf16_to_cpu(ehdr.e_type);
290968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_machine   = elf16_to_cpu(ehdr.e_machine);
291968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_version   = elf32_to_cpu(ehdr.e_version);
292968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_entry     = elf32_to_cpu(ehdr.e_entry);
293968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_phoff     = elf32_to_cpu(ehdr.e_phoff);
294968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_shoff     = elf32_to_cpu(ehdr.e_shoff);
295968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_flags     = elf32_to_cpu(ehdr.e_flags);
296968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_ehsize    = elf16_to_cpu(ehdr.e_ehsize);
297968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize);
298968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_phnum     = elf16_to_cpu(ehdr.e_phnum);
299968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize);
300968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_shnum     = elf16_to_cpu(ehdr.e_shnum);
301968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	ehdr.e_shstrndx  = elf16_to_cpu(ehdr.e_shstrndx);
302968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
303968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
304968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Unsupported ELF header type\n");
305968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
306968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_machine != EM_386) {
307968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Not for x86\n");
308968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
309968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_version != EV_CURRENT) {
310968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Unknown ELF version\n");
311968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
312968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) {
313968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Bad Elf header size\n");
314968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
315968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) {
316968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Bad program header entry\n");
317968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
318968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) {
319968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Bad section header entry\n");
320968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
321968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (ehdr.e_shstrndx >= ehdr.e_shnum) {
322968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("String table index out of bounds\n");
323968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
324968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
325968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
326968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void read_shdrs(FILE *fp)
327968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
328968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i;
329908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	Elf32_Shdr shdr;
330908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin
331908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	secs = calloc(ehdr.e_shnum, sizeof(struct section));
332908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	if (!secs) {
333908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		die("Unable to allocate %d section headers\n",
334908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		    ehdr.e_shnum);
335968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
336968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
337968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Seek to %d failed: %s\n",
338968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			ehdr.e_shoff, strerror(errno));
339968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
340908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 0; i < ehdr.e_shnum; i++) {
341908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec = &secs[i];
342908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (fread(&shdr, sizeof shdr, 1, fp) != 1)
343908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			die("Cannot read ELF section headers %d/%d: %s\n",
344908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			    i, ehdr.e_shnum, strerror(errno));
345908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_name      = elf32_to_cpu(shdr.sh_name);
346908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_type      = elf32_to_cpu(shdr.sh_type);
347908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_flags     = elf32_to_cpu(shdr.sh_flags);
348908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_addr      = elf32_to_cpu(shdr.sh_addr);
349908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_offset    = elf32_to_cpu(shdr.sh_offset);
350908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_size      = elf32_to_cpu(shdr.sh_size);
351908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_link      = elf32_to_cpu(shdr.sh_link);
352908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_info      = elf32_to_cpu(shdr.sh_info);
353908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign);
354908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->shdr.sh_entsize   = elf32_to_cpu(shdr.sh_entsize);
355908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (sec->shdr.sh_link < ehdr.e_shnum)
356908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			sec->link = &secs[sec->shdr.sh_link];
357968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
358968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
359968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
360968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
361968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void read_strtabs(FILE *fp)
362968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
363968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i;
364908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 0; i < ehdr.e_shnum; i++) {
365908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec = &secs[i];
366908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (sec->shdr.sh_type != SHT_STRTAB) {
367968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
368968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
369908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->strtab = malloc(sec->shdr.sh_size);
370908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (!sec->strtab) {
371968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("malloc of %d bytes for strtab failed\n",
372908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin				sec->shdr.sh_size);
373968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
374908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
375968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("Seek to %d failed: %s\n",
376908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin				sec->shdr.sh_offset, strerror(errno));
377968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
378908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
379908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		    != sec->shdr.sh_size) {
380968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("Cannot read symbol table: %s\n",
381968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				strerror(errno));
382968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
383968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
384968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
385968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
386968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void read_symtabs(FILE *fp)
387968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
388968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i,j;
389908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 0; i < ehdr.e_shnum; i++) {
390908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec = &secs[i];
391908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (sec->shdr.sh_type != SHT_SYMTAB) {
392968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
393968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
394908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->symtab = malloc(sec->shdr.sh_size);
395908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (!sec->symtab) {
396968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("malloc of %d bytes for symtab failed\n",
397908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin				sec->shdr.sh_size);
398968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
399908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
400968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("Seek to %d failed: %s\n",
401908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin				sec->shdr.sh_offset, strerror(errno));
402968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
403908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
404908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		    != sec->shdr.sh_size) {
405968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("Cannot read symbol table: %s\n",
406968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				strerror(errno));
407968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
408908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
409908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			Elf32_Sym *sym = &sec->symtab[j];
410908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			sym->st_name  = elf32_to_cpu(sym->st_name);
411908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			sym->st_value = elf32_to_cpu(sym->st_value);
412908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			sym->st_size  = elf32_to_cpu(sym->st_size);
413908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			sym->st_shndx = elf16_to_cpu(sym->st_shndx);
414968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
415968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
416968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
417968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
418968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
419968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void read_relocs(FILE *fp)
420968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
421968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i,j;
422908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 0; i < ehdr.e_shnum; i++) {
423908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec = &secs[i];
424908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (sec->shdr.sh_type != SHT_REL) {
425968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
426968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
427908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec->reltab = malloc(sec->shdr.sh_size);
428908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (!sec->reltab) {
429968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("malloc of %d bytes for relocs failed\n",
430908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin				sec->shdr.sh_size);
431968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
432908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
433968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("Seek to %d failed: %s\n",
434908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin				sec->shdr.sh_offset, strerror(errno));
435968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
436908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
437908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		    != sec->shdr.sh_size) {
438968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			die("Cannot read symbol table: %s\n",
439968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				strerror(errno));
440968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
441908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
442908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			Elf32_Rel *rel = &sec->reltab[j];
443908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			rel->r_offset = elf32_to_cpu(rel->r_offset);
444908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			rel->r_info   = elf32_to_cpu(rel->r_info);
445968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
446968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
447968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
448968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
449968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
450968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void print_absolute_symbols(void)
451968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
452968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i;
453968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	printf("Absolute symbols\n");
454968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
455908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 0; i < ehdr.e_shnum; i++) {
456908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec = &secs[i];
457968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		char *sym_strtab;
458968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		int j;
459908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin
460908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (sec->shdr.sh_type != SHT_SYMTAB) {
461968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
462968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
463908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sym_strtab = sec->link->strtab;
464908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) {
465968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			Elf32_Sym *sym;
466968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			const char *name;
467908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			sym = &sec->symtab[j];
468968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			name = sym_name(sym_strtab, sym);
469968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			if (sym->st_shndx != SHN_ABS) {
470968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				continue;
471968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			}
472968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			printf("%5d %08x %5d %10s %10s %12s %s\n",
473968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				j, sym->st_value, sym->st_size,
474968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				sym_type(ELF32_ST_TYPE(sym->st_info)),
475968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				sym_bind(ELF32_ST_BIND(sym->st_info)),
476968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)),
477968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				name);
478968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
479968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
480968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	printf("\n");
481968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
482968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
483968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void print_absolute_relocs(void)
484968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
4856a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	int i, printed = 0;
4866a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
487908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 0; i < ehdr.e_shnum; i++) {
488908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec = &secs[i];
489908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec_applies, *sec_symtab;
490968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		char *sym_strtab;
491968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		Elf32_Sym *sh_symtab;
492968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		int j;
493908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (sec->shdr.sh_type != SHT_REL) {
494968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
495968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
496908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec_symtab  = sec->link;
497908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec_applies = &secs[sec->shdr.sh_info];
498908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
499968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
500968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
501908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sh_symtab  = sec_symtab->symtab;
502908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sym_strtab = sec_symtab->link->strtab;
503908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
504968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			Elf32_Rel *rel;
505968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			Elf32_Sym *sym;
506968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			const char *name;
507908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			rel = &sec->reltab[j];
508968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
509968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			name = sym_name(sym_strtab, sym);
510968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			if (sym->st_shndx != SHN_ABS) {
511968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				continue;
512968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			}
5136a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
5146a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			/* Absolute symbols are not relocated if bzImage is
5156a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * loaded at a non-compiled address. Display a warning
5166a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * to user at compile time about the absolute
5176a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * relocations present.
5186a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 *
5196a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * User need to audit the code to make sure
5206a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * some symbols which should have been section
5216a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * relative have not become absolute because of some
5226a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * linker optimization or wrong programming usage.
5236a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 *
5246a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * Before warning check if this absolute symbol
5256a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 * relocation is harmless.
5266a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			 */
5276520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
5286a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal				continue;
5296a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
5306a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			if (!printed) {
5316a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal				printf("WARNING: Absolute relocations"
5326a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal					" present\n");
5336a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal				printf("Offset     Info     Type     Sym.Value "
5346a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal					"Sym.Name\n");
5356a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal				printed = 1;
5366a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			}
5376a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
538968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			printf("%08x %08x %10s %08x  %s\n",
539968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				rel->r_offset,
540968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				rel->r_info,
541968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				rel_type(ELF32_R_TYPE(rel->r_info)),
542968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				sym->st_value,
543968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				name);
544968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
545968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
5466a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal
5476a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	if (printed)
5486a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal		printf("\n");
549968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
550968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
5516520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
5526520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			int use_real_mode)
553968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
554968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i;
555968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	/* Walk through the relocations */
556908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 0; i < ehdr.e_shnum; i++) {
557968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		char *sym_strtab;
558968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		Elf32_Sym *sh_symtab;
559908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec_applies, *sec_symtab;
560968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		int j;
561908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		struct section *sec = &secs[i];
562908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin
563908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (sec->shdr.sh_type != SHT_REL) {
564968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
565968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
566908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec_symtab  = sec->link;
567908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sec_applies = &secs[sec->shdr.sh_info];
568908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
569968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
570968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
571908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		sh_symtab = sec_symtab->symtab;
572cc65f1ec192dc54de57483194502e9fa00934c39H. Peter Anvin		sym_strtab = sec_symtab->link->strtab;
573908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) {
574968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			Elf32_Rel *rel;
575968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			Elf32_Sym *sym;
576968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			unsigned r_type;
5776520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			const char *symname;
57824ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin			int shn_abs;
57924ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin
580908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin			rel = &sec->reltab[j];
581968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			sym = &sh_symtab[ELF32_R_SYM(rel->r_info)];
582968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			r_type = ELF32_R_TYPE(rel->r_info);
5836520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
58424ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin			shn_abs = sym->st_shndx == SHN_ABS;
58524ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin
586873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin			switch (r_type) {
587873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin			case R_386_NONE:
588873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin			case R_386_PC32:
5896520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			case R_386_PC16:
5906520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			case R_386_PC8:
59146176b4f6bac19454b7b5c35f68594b85850a600Tejun Heo				/*
59246176b4f6bac19454b7b5c35f68594b85850a600Tejun Heo				 * NONE can be ignored and and PC relative
59346176b4f6bac19454b7b5c35f68594b85850a600Tejun Heo				 * relocations don't need to be adjusted.
59446176b4f6bac19454b7b5c35f68594b85850a600Tejun Heo				 */
595873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin				break;
5966520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
5976520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			case R_386_16:
5986520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				symname = sym_name(sym_strtab, sym);
5996520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				if (!use_real_mode)
6006520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					goto bad;
60124ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin				if (shn_abs) {
6026520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					if (is_reloc(S_ABS, symname))
6036520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin						break;
6046520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					else if (!is_reloc(S_SEG, symname))
6056520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin						goto bad;
6066520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				} else {
6076520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					if (is_reloc(S_LIN, symname))
6086520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin						goto bad;
6096520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					else
6106520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin						break;
6116520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				}
6126520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				visit(rel, sym);
6136520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				break;
6146520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
615873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin			case R_386_32:
6166520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				symname = sym_name(sym_strtab, sym);
61724ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin				if (shn_abs) {
6186520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					if (is_reloc(S_ABS, symname))
6196520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin						break;
6206520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					else if (!is_reloc(S_REL, symname))
6216520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin						goto bad;
6226520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				} else {
6236520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					if (use_real_mode &&
6246520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin					    !is_reloc(S_LIN, symname))
6256520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin						break;
6266520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				}
627968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				visit(rel, sym);
628873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin				break;
629873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin			default:
630873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin				die("Unsupported relocation type: %s (%d)\n",
631873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin				    rel_type(r_type), r_type);
632873b5271f878a11729fb4602c6ce967d0ff81119H. Peter Anvin				break;
6336520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			bad:
6346520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				symname = sym_name(sym_strtab, sym);
63524ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin				die("Invalid %s %s relocation: %s\n",
63624ab82bd9bf18f3efc69a131d73577940941e1b7H. Peter Anvin				    shn_abs ? "absolute" : "relative",
6376520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				    rel_type(r_type), symname);
638968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			}
639968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
640968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
641968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
642968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
643968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
644968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
6456520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	if (ELF32_R_TYPE(rel->r_info) == R_386_16)
6466520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		reloc16_count++;
6476520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	else
6486520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		reloc_count++;
649968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
650968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
651968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym)
652968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
653968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	/* Remember the address that needs to be adjusted. */
6546520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	if (ELF32_R_TYPE(rel->r_info) == R_386_16)
6556520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		relocs16[reloc16_idx++] = rel->r_offset;
6566520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	else
6576520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		relocs[reloc_idx++] = rel->r_offset;
658968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
659968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
660968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic int cmp_relocs(const void *va, const void *vb)
661968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
662968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const unsigned long *a, *b;
663968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	a = va; b = vb;
664968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return (*a == *b)? 0 : (*a > *b)? 1 : -1;
665968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
666968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
6676520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic int write32(unsigned int v, FILE *f)
6686520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin{
6696520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	unsigned char buf[4];
6706520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
6716520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	put_unaligned_le32(v, buf);
6726520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
6736520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin}
6746520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
6756520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvinstatic void emit_relocs(int as_text, int use_real_mode)
676968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
677968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i;
678968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	/* Count how many relocations I have and allocate space for them. */
679968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	reloc_count = 0;
6806520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	walk_relocs(count_reloc, use_real_mode);
681968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	relocs = malloc(reloc_count * sizeof(relocs[0]));
682968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (!relocs) {
683968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("malloc of %d entries for relocs failed\n",
684968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			reloc_count);
685968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
6866520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
6876520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
6886520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	if (!relocs16) {
6896520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		die("malloc of %d entries for relocs16 failed\n",
6906520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			reloc16_count);
6916520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	}
692968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	/* Collect up the relocations */
693968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	reloc_idx = 0;
6946520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	walk_relocs(collect_reloc, use_real_mode);
6956520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
6966520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	if (reloc16_count && !use_real_mode)
6976520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		die("Segment relocations found but --realmode not specified\n");
698968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
699968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	/* Order the relocations for more efficient processing */
700968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs);
7016520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs);
702968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
703968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	/* Print the relocations */
704968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (as_text) {
705968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		/* Print the relocations in a form suitable that
706968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		 * gas will like.
707968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		 */
708968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		printf(".section \".data.reloc\",\"a\"\n");
709968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		printf(".balign 4\n");
7106520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		if (use_real_mode) {
7116520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			printf("\t.long %lu\n", reloc16_count);
7126520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			for (i = 0; i < reloc16_count; i++)
7136520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				printf("\t.long 0x%08lx\n", relocs16[i]);
7146520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			printf("\t.long %lu\n", reloc_count);
7156520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			for (i = 0; i < reloc_count; i++) {
7166520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				printf("\t.long 0x%08lx\n", relocs[i]);
7176520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			}
7186520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		} else {
7196520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			/* Print a stop */
7206520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			printf("\t.long 0x%08lx\n", (unsigned long)0);
7216520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			for (i = 0; i < reloc_count; i++) {
7226520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				printf("\t.long 0x%08lx\n", relocs[i]);
7236520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			}
724968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
7256520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
726968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		printf("\n");
727968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
728968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	else {
7296520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		if (use_real_mode) {
7306520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			write32(reloc16_count, stdout);
7316520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			for (i = 0; i < reloc16_count; i++)
7326520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				write32(relocs16[i], stdout);
7336520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			write32(reloc_count, stdout);
7346520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
7356520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			/* Now print each relocation */
7366520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			for (i = 0; i < reloc_count; i++)
7376520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				write32(relocs[i], stdout);
7386520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin		} else {
7396520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			/* Print a stop */
7406520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			write32(0, stdout);
7416520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin
7426520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			/* Now print each relocation */
7436520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			for (i = 0; i < reloc_count; i++) {
7446520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				write32(relocs[i], stdout);
7456520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			}
746968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
747968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
748968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
749968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
750968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanstatic void usage(void)
751968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
7526520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
753968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
754968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
755968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biedermanint main(int argc, char **argv)
756968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman{
7576a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	int show_absolute_syms, show_absolute_relocs;
7586520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	int as_text, use_real_mode;
759968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	const char *fname;
760968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	FILE *fp;
761968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	int i;
762968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman
7636a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	show_absolute_syms = 0;
7646a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	show_absolute_relocs = 0;
765968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	as_text = 0;
7666520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	use_real_mode = 0;
767968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	fname = NULL;
768908ec7afacfdc83dc10938ed1d3c38b3526034ecH. Peter Anvin	for (i = 1; i < argc; i++) {
769968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		char *arg = argv[i];
770968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		if (*arg == '-') {
7716520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			if (strcmp(arg, "--abs-syms") == 0) {
7726a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal				show_absolute_syms = 1;
7736a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal				continue;
7746a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal			}
7756520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			if (strcmp(arg, "--abs-relocs") == 0) {
7766a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal				show_absolute_relocs = 1;
777968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				continue;
778968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			}
7796520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			if (strcmp(arg, "--text") == 0) {
780968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				as_text = 1;
781968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman				continue;
782968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			}
7836520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			if (strcmp(arg, "--realmode") == 0) {
7846520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				use_real_mode = 1;
7856520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin				continue;
7866520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin			}
787968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
788968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		else if (!fname) {
789968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			fname = arg;
790968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			continue;
791968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		}
792968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		usage();
793968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
794968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (!fname) {
795968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		usage();
796968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
7976520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	regex_init(use_real_mode);
798968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	fp = fopen(fname, "r");
799968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	if (!fp) {
800968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		die("Cannot open %s: %s\n",
801968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman			fname, strerror(errno));
802968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
803968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	read_ehdr(fp);
804968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	read_shdrs(fp);
805968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	read_strtabs(fp);
806968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	read_symtabs(fp);
807968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	read_relocs(fp);
8086a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	if (show_absolute_syms) {
809968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		print_absolute_symbols();
8106a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal		return 0;
8116a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	}
8126a044b3a0a1829ef19bb29548ffe553f48e8d80cVivek Goyal	if (show_absolute_relocs) {
813968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		print_absolute_relocs();
814968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman		return 0;
815968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	}
8166520fe5564acf07ade7b18a1272db1184835c487H. Peter Anvin	emit_relocs(as_text, use_real_mode);
817968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman	return 0;
818968de4f02621db35b8ae5239c8cfc6664fb872d8Eric W. Biederman}
819