162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* This is included from relocs_32/64.c */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#define ElfW(type)		_ElfW(ELF_BITS, type)
562306a36Sopenharmony_ci#define _ElfW(bits, type)	__ElfW(bits, type)
662306a36Sopenharmony_ci#define __ElfW(bits, type)	Elf##bits##_##type
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#define Elf_Addr		ElfW(Addr)
962306a36Sopenharmony_ci#define Elf_Ehdr		ElfW(Ehdr)
1062306a36Sopenharmony_ci#define Elf_Phdr		ElfW(Phdr)
1162306a36Sopenharmony_ci#define Elf_Shdr		ElfW(Shdr)
1262306a36Sopenharmony_ci#define Elf_Sym			ElfW(Sym)
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic Elf_Ehdr		ehdr;
1562306a36Sopenharmony_cistatic unsigned long	shnum;
1662306a36Sopenharmony_cistatic unsigned int	shstrndx;
1762306a36Sopenharmony_cistatic unsigned int	shsymtabndx;
1862306a36Sopenharmony_cistatic unsigned int	shxsymtabndx;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int sym_index(Elf_Sym *sym);
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct relocs {
2362306a36Sopenharmony_ci	uint32_t	*offset;
2462306a36Sopenharmony_ci	unsigned long	count;
2562306a36Sopenharmony_ci	unsigned long	size;
2662306a36Sopenharmony_ci};
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic struct relocs relocs16;
2962306a36Sopenharmony_cistatic struct relocs relocs32;
3062306a36Sopenharmony_ci#if ELF_BITS == 64
3162306a36Sopenharmony_cistatic struct relocs relocs32neg;
3262306a36Sopenharmony_cistatic struct relocs relocs64;
3362306a36Sopenharmony_ci#define FMT PRIu64
3462306a36Sopenharmony_ci#else
3562306a36Sopenharmony_ci#define FMT PRIu32
3662306a36Sopenharmony_ci#endif
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistruct section {
3962306a36Sopenharmony_ci	Elf_Shdr       shdr;
4062306a36Sopenharmony_ci	struct section *link;
4162306a36Sopenharmony_ci	Elf_Sym        *symtab;
4262306a36Sopenharmony_ci	Elf32_Word     *xsymtab;
4362306a36Sopenharmony_ci	Elf_Rel        *reltab;
4462306a36Sopenharmony_ci	char           *strtab;
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_cistatic struct section *secs;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cistatic const char * const sym_regex_kernel[S_NSYMTYPES] = {
4962306a36Sopenharmony_ci/*
5062306a36Sopenharmony_ci * Following symbols have been audited. There values are constant and do
5162306a36Sopenharmony_ci * not change if bzImage is loaded at a different physical address than
5262306a36Sopenharmony_ci * the address for which it has been compiled. Don't warn user about
5362306a36Sopenharmony_ci * absolute relocations present w.r.t these symbols.
5462306a36Sopenharmony_ci */
5562306a36Sopenharmony_ci	[S_ABS] =
5662306a36Sopenharmony_ci	"^(xen_irq_disable_direct_reloc$|"
5762306a36Sopenharmony_ci	"xen_save_fl_direct_reloc$|"
5862306a36Sopenharmony_ci	"VDSO|"
5962306a36Sopenharmony_ci	"__kcfi_typeid_|"
6062306a36Sopenharmony_ci	"__crc_)",
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci/*
6362306a36Sopenharmony_ci * These symbols are known to be relative, even if the linker marks them
6462306a36Sopenharmony_ci * as absolute (typically defined outside any section in the linker script.)
6562306a36Sopenharmony_ci */
6662306a36Sopenharmony_ci	[S_REL] =
6762306a36Sopenharmony_ci	"^(__init_(begin|end)|"
6862306a36Sopenharmony_ci	"__x86_cpu_dev_(start|end)|"
6962306a36Sopenharmony_ci	"(__parainstructions|__alt_instructions)(_end)?|"
7062306a36Sopenharmony_ci	"(__iommu_table|__apicdrivers|__smp_locks)(_end)?|"
7162306a36Sopenharmony_ci	"__(start|end)_pci_.*|"
7262306a36Sopenharmony_ci#if CONFIG_FW_LOADER
7362306a36Sopenharmony_ci	"__(start|end)_builtin_fw|"
7462306a36Sopenharmony_ci#endif
7562306a36Sopenharmony_ci	"__(start|stop)___ksymtab(_gpl)?|"
7662306a36Sopenharmony_ci	"__(start|stop)___kcrctab(_gpl)?|"
7762306a36Sopenharmony_ci	"__(start|stop)___param|"
7862306a36Sopenharmony_ci	"__(start|stop)___modver|"
7962306a36Sopenharmony_ci	"__(start|stop)___bug_table|"
8062306a36Sopenharmony_ci	"__tracedata_(start|end)|"
8162306a36Sopenharmony_ci	"__(start|stop)_notes|"
8262306a36Sopenharmony_ci	"__end_rodata|"
8362306a36Sopenharmony_ci	"__end_rodata_aligned|"
8462306a36Sopenharmony_ci	"__initramfs_start|"
8562306a36Sopenharmony_ci	"(jiffies|jiffies_64)|"
8662306a36Sopenharmony_ci#if ELF_BITS == 64
8762306a36Sopenharmony_ci	"__per_cpu_load|"
8862306a36Sopenharmony_ci	"init_per_cpu__.*|"
8962306a36Sopenharmony_ci	"__end_rodata_hpage_align|"
9062306a36Sopenharmony_ci#endif
9162306a36Sopenharmony_ci	"__vvar_page|"
9262306a36Sopenharmony_ci	"_end)$"
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic const char * const sym_regex_realmode[S_NSYMTYPES] = {
9762306a36Sopenharmony_ci/*
9862306a36Sopenharmony_ci * These symbols are known to be relative, even if the linker marks them
9962306a36Sopenharmony_ci * as absolute (typically defined outside any section in the linker script.)
10062306a36Sopenharmony_ci */
10162306a36Sopenharmony_ci	[S_REL] =
10262306a36Sopenharmony_ci	"^pa_",
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci/*
10562306a36Sopenharmony_ci * These are 16-bit segment symbols when compiling 16-bit code.
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_ci	[S_SEG] =
10862306a36Sopenharmony_ci	"^real_mode_seg$",
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci/*
11162306a36Sopenharmony_ci * These are offsets belonging to segments, as opposed to linear addresses,
11262306a36Sopenharmony_ci * when compiling 16-bit code.
11362306a36Sopenharmony_ci */
11462306a36Sopenharmony_ci	[S_LIN] =
11562306a36Sopenharmony_ci	"^pa_",
11662306a36Sopenharmony_ci};
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic const char * const *sym_regex;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic regex_t sym_regex_c[S_NSYMTYPES];
12162306a36Sopenharmony_cistatic int is_reloc(enum symtype type, const char *sym_name)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	return sym_regex[type] &&
12462306a36Sopenharmony_ci		!regexec(&sym_regex_c[type], sym_name, 0, NULL, 0);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic void regex_init(int use_real_mode)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci        char errbuf[128];
13062306a36Sopenharmony_ci        int err;
13162306a36Sopenharmony_ci	int i;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	if (use_real_mode)
13462306a36Sopenharmony_ci		sym_regex = sym_regex_realmode;
13562306a36Sopenharmony_ci	else
13662306a36Sopenharmony_ci		sym_regex = sym_regex_kernel;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	for (i = 0; i < S_NSYMTYPES; i++) {
13962306a36Sopenharmony_ci		if (!sym_regex[i])
14062306a36Sopenharmony_ci			continue;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		err = regcomp(&sym_regex_c[i], sym_regex[i],
14362306a36Sopenharmony_ci			      REG_EXTENDED|REG_NOSUB);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci		if (err) {
14662306a36Sopenharmony_ci			regerror(err, &sym_regex_c[i], errbuf, sizeof(errbuf));
14762306a36Sopenharmony_ci			die("%s", errbuf);
14862306a36Sopenharmony_ci		}
14962306a36Sopenharmony_ci        }
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic const char *sym_type(unsigned type)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	static const char *type_name[] = {
15562306a36Sopenharmony_ci#define SYM_TYPE(X) [X] = #X
15662306a36Sopenharmony_ci		SYM_TYPE(STT_NOTYPE),
15762306a36Sopenharmony_ci		SYM_TYPE(STT_OBJECT),
15862306a36Sopenharmony_ci		SYM_TYPE(STT_FUNC),
15962306a36Sopenharmony_ci		SYM_TYPE(STT_SECTION),
16062306a36Sopenharmony_ci		SYM_TYPE(STT_FILE),
16162306a36Sopenharmony_ci		SYM_TYPE(STT_COMMON),
16262306a36Sopenharmony_ci		SYM_TYPE(STT_TLS),
16362306a36Sopenharmony_ci#undef SYM_TYPE
16462306a36Sopenharmony_ci	};
16562306a36Sopenharmony_ci	const char *name = "unknown sym type name";
16662306a36Sopenharmony_ci	if (type < ARRAY_SIZE(type_name)) {
16762306a36Sopenharmony_ci		name = type_name[type];
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci	return name;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_cistatic const char *sym_bind(unsigned bind)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	static const char *bind_name[] = {
17562306a36Sopenharmony_ci#define SYM_BIND(X) [X] = #X
17662306a36Sopenharmony_ci		SYM_BIND(STB_LOCAL),
17762306a36Sopenharmony_ci		SYM_BIND(STB_GLOBAL),
17862306a36Sopenharmony_ci		SYM_BIND(STB_WEAK),
17962306a36Sopenharmony_ci#undef SYM_BIND
18062306a36Sopenharmony_ci	};
18162306a36Sopenharmony_ci	const char *name = "unknown sym bind name";
18262306a36Sopenharmony_ci	if (bind < ARRAY_SIZE(bind_name)) {
18362306a36Sopenharmony_ci		name = bind_name[bind];
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci	return name;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic const char *sym_visibility(unsigned visibility)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	static const char *visibility_name[] = {
19162306a36Sopenharmony_ci#define SYM_VISIBILITY(X) [X] = #X
19262306a36Sopenharmony_ci		SYM_VISIBILITY(STV_DEFAULT),
19362306a36Sopenharmony_ci		SYM_VISIBILITY(STV_INTERNAL),
19462306a36Sopenharmony_ci		SYM_VISIBILITY(STV_HIDDEN),
19562306a36Sopenharmony_ci		SYM_VISIBILITY(STV_PROTECTED),
19662306a36Sopenharmony_ci#undef SYM_VISIBILITY
19762306a36Sopenharmony_ci	};
19862306a36Sopenharmony_ci	const char *name = "unknown sym visibility name";
19962306a36Sopenharmony_ci	if (visibility < ARRAY_SIZE(visibility_name)) {
20062306a36Sopenharmony_ci		name = visibility_name[visibility];
20162306a36Sopenharmony_ci	}
20262306a36Sopenharmony_ci	return name;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic const char *rel_type(unsigned type)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	static const char *type_name[] = {
20862306a36Sopenharmony_ci#define REL_TYPE(X) [X] = #X
20962306a36Sopenharmony_ci#if ELF_BITS == 64
21062306a36Sopenharmony_ci		REL_TYPE(R_X86_64_NONE),
21162306a36Sopenharmony_ci		REL_TYPE(R_X86_64_64),
21262306a36Sopenharmony_ci		REL_TYPE(R_X86_64_PC64),
21362306a36Sopenharmony_ci		REL_TYPE(R_X86_64_PC32),
21462306a36Sopenharmony_ci		REL_TYPE(R_X86_64_GOT32),
21562306a36Sopenharmony_ci		REL_TYPE(R_X86_64_PLT32),
21662306a36Sopenharmony_ci		REL_TYPE(R_X86_64_COPY),
21762306a36Sopenharmony_ci		REL_TYPE(R_X86_64_GLOB_DAT),
21862306a36Sopenharmony_ci		REL_TYPE(R_X86_64_JUMP_SLOT),
21962306a36Sopenharmony_ci		REL_TYPE(R_X86_64_RELATIVE),
22062306a36Sopenharmony_ci		REL_TYPE(R_X86_64_GOTPCREL),
22162306a36Sopenharmony_ci		REL_TYPE(R_X86_64_32),
22262306a36Sopenharmony_ci		REL_TYPE(R_X86_64_32S),
22362306a36Sopenharmony_ci		REL_TYPE(R_X86_64_16),
22462306a36Sopenharmony_ci		REL_TYPE(R_X86_64_PC16),
22562306a36Sopenharmony_ci		REL_TYPE(R_X86_64_8),
22662306a36Sopenharmony_ci		REL_TYPE(R_X86_64_PC8),
22762306a36Sopenharmony_ci#else
22862306a36Sopenharmony_ci		REL_TYPE(R_386_NONE),
22962306a36Sopenharmony_ci		REL_TYPE(R_386_32),
23062306a36Sopenharmony_ci		REL_TYPE(R_386_PC32),
23162306a36Sopenharmony_ci		REL_TYPE(R_386_GOT32),
23262306a36Sopenharmony_ci		REL_TYPE(R_386_PLT32),
23362306a36Sopenharmony_ci		REL_TYPE(R_386_COPY),
23462306a36Sopenharmony_ci		REL_TYPE(R_386_GLOB_DAT),
23562306a36Sopenharmony_ci		REL_TYPE(R_386_JMP_SLOT),
23662306a36Sopenharmony_ci		REL_TYPE(R_386_RELATIVE),
23762306a36Sopenharmony_ci		REL_TYPE(R_386_GOTOFF),
23862306a36Sopenharmony_ci		REL_TYPE(R_386_GOTPC),
23962306a36Sopenharmony_ci		REL_TYPE(R_386_8),
24062306a36Sopenharmony_ci		REL_TYPE(R_386_PC8),
24162306a36Sopenharmony_ci		REL_TYPE(R_386_16),
24262306a36Sopenharmony_ci		REL_TYPE(R_386_PC16),
24362306a36Sopenharmony_ci#endif
24462306a36Sopenharmony_ci#undef REL_TYPE
24562306a36Sopenharmony_ci	};
24662306a36Sopenharmony_ci	const char *name = "unknown type rel type name";
24762306a36Sopenharmony_ci	if (type < ARRAY_SIZE(type_name) && type_name[type]) {
24862306a36Sopenharmony_ci		name = type_name[type];
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	return name;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic const char *sec_name(unsigned shndx)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	const char *sec_strtab;
25662306a36Sopenharmony_ci	const char *name;
25762306a36Sopenharmony_ci	sec_strtab = secs[shstrndx].strtab;
25862306a36Sopenharmony_ci	name = "<noname>";
25962306a36Sopenharmony_ci	if (shndx < shnum) {
26062306a36Sopenharmony_ci		name = sec_strtab + secs[shndx].shdr.sh_name;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci	else if (shndx == SHN_ABS) {
26362306a36Sopenharmony_ci		name = "ABSOLUTE";
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci	else if (shndx == SHN_COMMON) {
26662306a36Sopenharmony_ci		name = "COMMON";
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci	return name;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	const char *name;
27462306a36Sopenharmony_ci	name = "<noname>";
27562306a36Sopenharmony_ci	if (sym->st_name) {
27662306a36Sopenharmony_ci		name = sym_strtab + sym->st_name;
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci	else {
27962306a36Sopenharmony_ci		name = sec_name(sym_index(sym));
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci	return name;
28262306a36Sopenharmony_ci}
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_cistatic Elf_Sym *sym_lookup(const char *symname)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	int i;
28762306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
28862306a36Sopenharmony_ci		struct section *sec = &secs[i];
28962306a36Sopenharmony_ci		long nsyms;
29062306a36Sopenharmony_ci		char *strtab;
29162306a36Sopenharmony_ci		Elf_Sym *symtab;
29262306a36Sopenharmony_ci		Elf_Sym *sym;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		if (sec->shdr.sh_type != SHT_SYMTAB)
29562306a36Sopenharmony_ci			continue;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci		nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
29862306a36Sopenharmony_ci		symtab = sec->symtab;
29962306a36Sopenharmony_ci		strtab = sec->link->strtab;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci		for (sym = symtab; --nsyms >= 0; sym++) {
30262306a36Sopenharmony_ci			if (!sym->st_name)
30362306a36Sopenharmony_ci				continue;
30462306a36Sopenharmony_ci			if (strcmp(symname, strtab + sym->st_name) == 0)
30562306a36Sopenharmony_ci				return sym;
30662306a36Sopenharmony_ci		}
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci	return 0;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci#if BYTE_ORDER == LITTLE_ENDIAN
31262306a36Sopenharmony_ci#define le16_to_cpu(val) (val)
31362306a36Sopenharmony_ci#define le32_to_cpu(val) (val)
31462306a36Sopenharmony_ci#define le64_to_cpu(val) (val)
31562306a36Sopenharmony_ci#endif
31662306a36Sopenharmony_ci#if BYTE_ORDER == BIG_ENDIAN
31762306a36Sopenharmony_ci#define le16_to_cpu(val) bswap_16(val)
31862306a36Sopenharmony_ci#define le32_to_cpu(val) bswap_32(val)
31962306a36Sopenharmony_ci#define le64_to_cpu(val) bswap_64(val)
32062306a36Sopenharmony_ci#endif
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic uint16_t elf16_to_cpu(uint16_t val)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	return le16_to_cpu(val);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic uint32_t elf32_to_cpu(uint32_t val)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	return le32_to_cpu(val);
33062306a36Sopenharmony_ci}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci#define elf_half_to_cpu(x)	elf16_to_cpu(x)
33362306a36Sopenharmony_ci#define elf_word_to_cpu(x)	elf32_to_cpu(x)
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci#if ELF_BITS == 64
33662306a36Sopenharmony_cistatic uint64_t elf64_to_cpu(uint64_t val)
33762306a36Sopenharmony_ci{
33862306a36Sopenharmony_ci        return le64_to_cpu(val);
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci#define elf_addr_to_cpu(x)	elf64_to_cpu(x)
34162306a36Sopenharmony_ci#define elf_off_to_cpu(x)	elf64_to_cpu(x)
34262306a36Sopenharmony_ci#define elf_xword_to_cpu(x)	elf64_to_cpu(x)
34362306a36Sopenharmony_ci#else
34462306a36Sopenharmony_ci#define elf_addr_to_cpu(x)	elf32_to_cpu(x)
34562306a36Sopenharmony_ci#define elf_off_to_cpu(x)	elf32_to_cpu(x)
34662306a36Sopenharmony_ci#define elf_xword_to_cpu(x)	elf32_to_cpu(x)
34762306a36Sopenharmony_ci#endif
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_cistatic int sym_index(Elf_Sym *sym)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	Elf_Sym *symtab = secs[shsymtabndx].symtab;
35262306a36Sopenharmony_ci	Elf32_Word *xsymtab = secs[shxsymtabndx].xsymtab;
35362306a36Sopenharmony_ci	unsigned long offset;
35462306a36Sopenharmony_ci	int index;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (sym->st_shndx != SHN_XINDEX)
35762306a36Sopenharmony_ci		return sym->st_shndx;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	/* calculate offset of sym from head of table. */
36062306a36Sopenharmony_ci	offset = (unsigned long)sym - (unsigned long)symtab;
36162306a36Sopenharmony_ci	index = offset / sizeof(*sym);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	return elf32_to_cpu(xsymtab[index]);
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic void read_ehdr(FILE *fp)
36762306a36Sopenharmony_ci{
36862306a36Sopenharmony_ci	if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
36962306a36Sopenharmony_ci		die("Cannot read ELF header: %s\n",
37062306a36Sopenharmony_ci			strerror(errno));
37162306a36Sopenharmony_ci	}
37262306a36Sopenharmony_ci	if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
37362306a36Sopenharmony_ci		die("No ELF magic\n");
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci	if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) {
37662306a36Sopenharmony_ci		die("Not a %d bit executable\n", ELF_BITS);
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci	if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
37962306a36Sopenharmony_ci		die("Not a LSB ELF executable\n");
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci	if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) {
38262306a36Sopenharmony_ci		die("Unknown ELF version\n");
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	/* Convert the fields to native endian */
38562306a36Sopenharmony_ci	ehdr.e_type      = elf_half_to_cpu(ehdr.e_type);
38662306a36Sopenharmony_ci	ehdr.e_machine   = elf_half_to_cpu(ehdr.e_machine);
38762306a36Sopenharmony_ci	ehdr.e_version   = elf_word_to_cpu(ehdr.e_version);
38862306a36Sopenharmony_ci	ehdr.e_entry     = elf_addr_to_cpu(ehdr.e_entry);
38962306a36Sopenharmony_ci	ehdr.e_phoff     = elf_off_to_cpu(ehdr.e_phoff);
39062306a36Sopenharmony_ci	ehdr.e_shoff     = elf_off_to_cpu(ehdr.e_shoff);
39162306a36Sopenharmony_ci	ehdr.e_flags     = elf_word_to_cpu(ehdr.e_flags);
39262306a36Sopenharmony_ci	ehdr.e_ehsize    = elf_half_to_cpu(ehdr.e_ehsize);
39362306a36Sopenharmony_ci	ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
39462306a36Sopenharmony_ci	ehdr.e_phnum     = elf_half_to_cpu(ehdr.e_phnum);
39562306a36Sopenharmony_ci	ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
39662306a36Sopenharmony_ci	ehdr.e_shnum     = elf_half_to_cpu(ehdr.e_shnum);
39762306a36Sopenharmony_ci	ehdr.e_shstrndx  = elf_half_to_cpu(ehdr.e_shstrndx);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	shnum = ehdr.e_shnum;
40062306a36Sopenharmony_ci	shstrndx = ehdr.e_shstrndx;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN))
40362306a36Sopenharmony_ci		die("Unsupported ELF header type\n");
40462306a36Sopenharmony_ci	if (ehdr.e_machine != ELF_MACHINE)
40562306a36Sopenharmony_ci		die("Not for %s\n", ELF_MACHINE_NAME);
40662306a36Sopenharmony_ci	if (ehdr.e_version != EV_CURRENT)
40762306a36Sopenharmony_ci		die("Unknown ELF version\n");
40862306a36Sopenharmony_ci	if (ehdr.e_ehsize != sizeof(Elf_Ehdr))
40962306a36Sopenharmony_ci		die("Bad ELF header size\n");
41062306a36Sopenharmony_ci	if (ehdr.e_phentsize != sizeof(Elf_Phdr))
41162306a36Sopenharmony_ci		die("Bad program header entry\n");
41262306a36Sopenharmony_ci	if (ehdr.e_shentsize != sizeof(Elf_Shdr))
41362306a36Sopenharmony_ci		die("Bad section header entry\n");
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	if (shnum == SHN_UNDEF || shstrndx == SHN_XINDEX) {
41762306a36Sopenharmony_ci		Elf_Shdr shdr;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0)
42062306a36Sopenharmony_ci			die("Seek to %" FMT " failed: %s\n", ehdr.e_shoff, strerror(errno));
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		if (fread(&shdr, sizeof(shdr), 1, fp) != 1)
42362306a36Sopenharmony_ci			die("Cannot read initial ELF section header: %s\n", strerror(errno));
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		if (shnum == SHN_UNDEF)
42662306a36Sopenharmony_ci			shnum = elf_xword_to_cpu(shdr.sh_size);
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci		if (shstrndx == SHN_XINDEX)
42962306a36Sopenharmony_ci			shstrndx = elf_word_to_cpu(shdr.sh_link);
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (shstrndx >= shnum)
43362306a36Sopenharmony_ci		die("String table index out of bounds\n");
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic void read_shdrs(FILE *fp)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	int i;
43962306a36Sopenharmony_ci	Elf_Shdr shdr;
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	secs = calloc(shnum, sizeof(struct section));
44262306a36Sopenharmony_ci	if (!secs) {
44362306a36Sopenharmony_ci		die("Unable to allocate %ld section headers\n",
44462306a36Sopenharmony_ci		    shnum);
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci	if (fseek(fp, ehdr.e_shoff, SEEK_SET) < 0) {
44762306a36Sopenharmony_ci		die("Seek to %" FMT " failed: %s\n",
44862306a36Sopenharmony_ci		    ehdr.e_shoff, strerror(errno));
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
45162306a36Sopenharmony_ci		struct section *sec = &secs[i];
45262306a36Sopenharmony_ci		if (fread(&shdr, sizeof(shdr), 1, fp) != 1)
45362306a36Sopenharmony_ci			die("Cannot read ELF section headers %d/%ld: %s\n",
45462306a36Sopenharmony_ci			    i, shnum, strerror(errno));
45562306a36Sopenharmony_ci		sec->shdr.sh_name      = elf_word_to_cpu(shdr.sh_name);
45662306a36Sopenharmony_ci		sec->shdr.sh_type      = elf_word_to_cpu(shdr.sh_type);
45762306a36Sopenharmony_ci		sec->shdr.sh_flags     = elf_xword_to_cpu(shdr.sh_flags);
45862306a36Sopenharmony_ci		sec->shdr.sh_addr      = elf_addr_to_cpu(shdr.sh_addr);
45962306a36Sopenharmony_ci		sec->shdr.sh_offset    = elf_off_to_cpu(shdr.sh_offset);
46062306a36Sopenharmony_ci		sec->shdr.sh_size      = elf_xword_to_cpu(shdr.sh_size);
46162306a36Sopenharmony_ci		sec->shdr.sh_link      = elf_word_to_cpu(shdr.sh_link);
46262306a36Sopenharmony_ci		sec->shdr.sh_info      = elf_word_to_cpu(shdr.sh_info);
46362306a36Sopenharmony_ci		sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
46462306a36Sopenharmony_ci		sec->shdr.sh_entsize   = elf_xword_to_cpu(shdr.sh_entsize);
46562306a36Sopenharmony_ci		if (sec->shdr.sh_link < shnum)
46662306a36Sopenharmony_ci			sec->link = &secs[sec->shdr.sh_link];
46762306a36Sopenharmony_ci	}
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_cistatic void read_strtabs(FILE *fp)
47262306a36Sopenharmony_ci{
47362306a36Sopenharmony_ci	int i;
47462306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
47562306a36Sopenharmony_ci		struct section *sec = &secs[i];
47662306a36Sopenharmony_ci		if (sec->shdr.sh_type != SHT_STRTAB) {
47762306a36Sopenharmony_ci			continue;
47862306a36Sopenharmony_ci		}
47962306a36Sopenharmony_ci		sec->strtab = malloc(sec->shdr.sh_size);
48062306a36Sopenharmony_ci		if (!sec->strtab) {
48162306a36Sopenharmony_ci			die("malloc of %" FMT " bytes for strtab failed\n",
48262306a36Sopenharmony_ci			    sec->shdr.sh_size);
48362306a36Sopenharmony_ci		}
48462306a36Sopenharmony_ci		if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
48562306a36Sopenharmony_ci			die("Seek to %" FMT " failed: %s\n",
48662306a36Sopenharmony_ci			    sec->shdr.sh_offset, strerror(errno));
48762306a36Sopenharmony_ci		}
48862306a36Sopenharmony_ci		if (fread(sec->strtab, 1, sec->shdr.sh_size, fp)
48962306a36Sopenharmony_ci		    != sec->shdr.sh_size) {
49062306a36Sopenharmony_ci			die("Cannot read symbol table: %s\n",
49162306a36Sopenharmony_ci				strerror(errno));
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_cistatic void read_symtabs(FILE *fp)
49762306a36Sopenharmony_ci{
49862306a36Sopenharmony_ci	int i,j;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
50162306a36Sopenharmony_ci		struct section *sec = &secs[i];
50262306a36Sopenharmony_ci		int num_syms;
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci		switch (sec->shdr.sh_type) {
50562306a36Sopenharmony_ci		case SHT_SYMTAB_SHNDX:
50662306a36Sopenharmony_ci			sec->xsymtab = malloc(sec->shdr.sh_size);
50762306a36Sopenharmony_ci			if (!sec->xsymtab) {
50862306a36Sopenharmony_ci				die("malloc of %" FMT " bytes for xsymtab failed\n",
50962306a36Sopenharmony_ci				    sec->shdr.sh_size);
51062306a36Sopenharmony_ci			}
51162306a36Sopenharmony_ci			if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
51262306a36Sopenharmony_ci				die("Seek to %" FMT " failed: %s\n",
51362306a36Sopenharmony_ci				    sec->shdr.sh_offset, strerror(errno));
51462306a36Sopenharmony_ci			}
51562306a36Sopenharmony_ci			if (fread(sec->xsymtab, 1, sec->shdr.sh_size, fp)
51662306a36Sopenharmony_ci			    != sec->shdr.sh_size) {
51762306a36Sopenharmony_ci				die("Cannot read extended symbol table: %s\n",
51862306a36Sopenharmony_ci				    strerror(errno));
51962306a36Sopenharmony_ci			}
52062306a36Sopenharmony_ci			shxsymtabndx = i;
52162306a36Sopenharmony_ci			continue;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		case SHT_SYMTAB:
52462306a36Sopenharmony_ci			num_syms = sec->shdr.sh_size / sizeof(Elf_Sym);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci			sec->symtab = malloc(sec->shdr.sh_size);
52762306a36Sopenharmony_ci			if (!sec->symtab) {
52862306a36Sopenharmony_ci				die("malloc of %" FMT " bytes for symtab failed\n",
52962306a36Sopenharmony_ci				    sec->shdr.sh_size);
53062306a36Sopenharmony_ci			}
53162306a36Sopenharmony_ci			if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
53262306a36Sopenharmony_ci				die("Seek to %" FMT " failed: %s\n",
53362306a36Sopenharmony_ci				    sec->shdr.sh_offset, strerror(errno));
53462306a36Sopenharmony_ci			}
53562306a36Sopenharmony_ci			if (fread(sec->symtab, 1, sec->shdr.sh_size, fp)
53662306a36Sopenharmony_ci			    != sec->shdr.sh_size) {
53762306a36Sopenharmony_ci				die("Cannot read symbol table: %s\n",
53862306a36Sopenharmony_ci				    strerror(errno));
53962306a36Sopenharmony_ci			}
54062306a36Sopenharmony_ci			for (j = 0; j < num_syms; j++) {
54162306a36Sopenharmony_ci				Elf_Sym *sym = &sec->symtab[j];
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci				sym->st_name  = elf_word_to_cpu(sym->st_name);
54462306a36Sopenharmony_ci				sym->st_value = elf_addr_to_cpu(sym->st_value);
54562306a36Sopenharmony_ci				sym->st_size  = elf_xword_to_cpu(sym->st_size);
54662306a36Sopenharmony_ci				sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
54762306a36Sopenharmony_ci			}
54862306a36Sopenharmony_ci			shsymtabndx = i;
54962306a36Sopenharmony_ci			continue;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci		default:
55262306a36Sopenharmony_ci			continue;
55362306a36Sopenharmony_ci		}
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void read_relocs(FILE *fp)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	int i,j;
56162306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
56262306a36Sopenharmony_ci		struct section *sec = &secs[i];
56362306a36Sopenharmony_ci		if (sec->shdr.sh_type != SHT_REL_TYPE) {
56462306a36Sopenharmony_ci			continue;
56562306a36Sopenharmony_ci		}
56662306a36Sopenharmony_ci		sec->reltab = malloc(sec->shdr.sh_size);
56762306a36Sopenharmony_ci		if (!sec->reltab) {
56862306a36Sopenharmony_ci			die("malloc of %" FMT " bytes for relocs failed\n",
56962306a36Sopenharmony_ci			    sec->shdr.sh_size);
57062306a36Sopenharmony_ci		}
57162306a36Sopenharmony_ci		if (fseek(fp, sec->shdr.sh_offset, SEEK_SET) < 0) {
57262306a36Sopenharmony_ci			die("Seek to %" FMT " failed: %s\n",
57362306a36Sopenharmony_ci			    sec->shdr.sh_offset, strerror(errno));
57462306a36Sopenharmony_ci		}
57562306a36Sopenharmony_ci		if (fread(sec->reltab, 1, sec->shdr.sh_size, fp)
57662306a36Sopenharmony_ci		    != sec->shdr.sh_size) {
57762306a36Sopenharmony_ci			die("Cannot read symbol table: %s\n",
57862306a36Sopenharmony_ci				strerror(errno));
57962306a36Sopenharmony_ci		}
58062306a36Sopenharmony_ci		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
58162306a36Sopenharmony_ci			Elf_Rel *rel = &sec->reltab[j];
58262306a36Sopenharmony_ci			rel->r_offset = elf_addr_to_cpu(rel->r_offset);
58362306a36Sopenharmony_ci			rel->r_info   = elf_xword_to_cpu(rel->r_info);
58462306a36Sopenharmony_ci#if (SHT_REL_TYPE == SHT_RELA)
58562306a36Sopenharmony_ci			rel->r_addend = elf_xword_to_cpu(rel->r_addend);
58662306a36Sopenharmony_ci#endif
58762306a36Sopenharmony_ci		}
58862306a36Sopenharmony_ci	}
58962306a36Sopenharmony_ci}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_cistatic void print_absolute_symbols(void)
59362306a36Sopenharmony_ci{
59462306a36Sopenharmony_ci	int i;
59562306a36Sopenharmony_ci	const char *format;
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci	if (ELF_BITS == 64)
59862306a36Sopenharmony_ci		format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n";
59962306a36Sopenharmony_ci	else
60062306a36Sopenharmony_ci		format = "%5d %08"PRIx32"  %5"PRId32" %10s %10s %12s %s\n";
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	printf("Absolute symbols\n");
60362306a36Sopenharmony_ci	printf(" Num:    Value Size  Type       Bind        Visibility  Name\n");
60462306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
60562306a36Sopenharmony_ci		struct section *sec = &secs[i];
60662306a36Sopenharmony_ci		char *sym_strtab;
60762306a36Sopenharmony_ci		int j;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci		if (sec->shdr.sh_type != SHT_SYMTAB) {
61062306a36Sopenharmony_ci			continue;
61162306a36Sopenharmony_ci		}
61262306a36Sopenharmony_ci		sym_strtab = sec->link->strtab;
61362306a36Sopenharmony_ci		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
61462306a36Sopenharmony_ci			Elf_Sym *sym;
61562306a36Sopenharmony_ci			const char *name;
61662306a36Sopenharmony_ci			sym = &sec->symtab[j];
61762306a36Sopenharmony_ci			name = sym_name(sym_strtab, sym);
61862306a36Sopenharmony_ci			if (sym->st_shndx != SHN_ABS) {
61962306a36Sopenharmony_ci				continue;
62062306a36Sopenharmony_ci			}
62162306a36Sopenharmony_ci			printf(format,
62262306a36Sopenharmony_ci				j, sym->st_value, sym->st_size,
62362306a36Sopenharmony_ci				sym_type(ELF_ST_TYPE(sym->st_info)),
62462306a36Sopenharmony_ci				sym_bind(ELF_ST_BIND(sym->st_info)),
62562306a36Sopenharmony_ci				sym_visibility(ELF_ST_VISIBILITY(sym->st_other)),
62662306a36Sopenharmony_ci				name);
62762306a36Sopenharmony_ci		}
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci	printf("\n");
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_cistatic void print_absolute_relocs(void)
63362306a36Sopenharmony_ci{
63462306a36Sopenharmony_ci	int i, printed = 0;
63562306a36Sopenharmony_ci	const char *format;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	if (ELF_BITS == 64)
63862306a36Sopenharmony_ci		format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64"  %s\n";
63962306a36Sopenharmony_ci	else
64062306a36Sopenharmony_ci		format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32"  %s\n";
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
64362306a36Sopenharmony_ci		struct section *sec = &secs[i];
64462306a36Sopenharmony_ci		struct section *sec_applies, *sec_symtab;
64562306a36Sopenharmony_ci		char *sym_strtab;
64662306a36Sopenharmony_ci		Elf_Sym *sh_symtab;
64762306a36Sopenharmony_ci		int j;
64862306a36Sopenharmony_ci		if (sec->shdr.sh_type != SHT_REL_TYPE) {
64962306a36Sopenharmony_ci			continue;
65062306a36Sopenharmony_ci		}
65162306a36Sopenharmony_ci		sec_symtab  = sec->link;
65262306a36Sopenharmony_ci		sec_applies = &secs[sec->shdr.sh_info];
65362306a36Sopenharmony_ci		if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
65462306a36Sopenharmony_ci			continue;
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci		/*
65762306a36Sopenharmony_ci		 * Do not perform relocations in .notes section; any
65862306a36Sopenharmony_ci		 * values there are meant for pre-boot consumption (e.g.
65962306a36Sopenharmony_ci		 * startup_xen).
66062306a36Sopenharmony_ci		 */
66162306a36Sopenharmony_ci		if (sec_applies->shdr.sh_type == SHT_NOTE) {
66262306a36Sopenharmony_ci			continue;
66362306a36Sopenharmony_ci		}
66462306a36Sopenharmony_ci		sh_symtab  = sec_symtab->symtab;
66562306a36Sopenharmony_ci		sym_strtab = sec_symtab->link->strtab;
66662306a36Sopenharmony_ci		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
66762306a36Sopenharmony_ci			Elf_Rel *rel;
66862306a36Sopenharmony_ci			Elf_Sym *sym;
66962306a36Sopenharmony_ci			const char *name;
67062306a36Sopenharmony_ci			rel = &sec->reltab[j];
67162306a36Sopenharmony_ci			sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
67262306a36Sopenharmony_ci			name = sym_name(sym_strtab, sym);
67362306a36Sopenharmony_ci			if (sym->st_shndx != SHN_ABS) {
67462306a36Sopenharmony_ci				continue;
67562306a36Sopenharmony_ci			}
67662306a36Sopenharmony_ci
67762306a36Sopenharmony_ci			/* Absolute symbols are not relocated if bzImage is
67862306a36Sopenharmony_ci			 * loaded at a non-compiled address. Display a warning
67962306a36Sopenharmony_ci			 * to user at compile time about the absolute
68062306a36Sopenharmony_ci			 * relocations present.
68162306a36Sopenharmony_ci			 *
68262306a36Sopenharmony_ci			 * User need to audit the code to make sure
68362306a36Sopenharmony_ci			 * some symbols which should have been section
68462306a36Sopenharmony_ci			 * relative have not become absolute because of some
68562306a36Sopenharmony_ci			 * linker optimization or wrong programming usage.
68662306a36Sopenharmony_ci			 *
68762306a36Sopenharmony_ci			 * Before warning check if this absolute symbol
68862306a36Sopenharmony_ci			 * relocation is harmless.
68962306a36Sopenharmony_ci			 */
69062306a36Sopenharmony_ci			if (is_reloc(S_ABS, name) || is_reloc(S_REL, name))
69162306a36Sopenharmony_ci				continue;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci			if (!printed) {
69462306a36Sopenharmony_ci				printf("WARNING: Absolute relocations"
69562306a36Sopenharmony_ci					" present\n");
69662306a36Sopenharmony_ci				printf("Offset     Info     Type     Sym.Value "
69762306a36Sopenharmony_ci					"Sym.Name\n");
69862306a36Sopenharmony_ci				printed = 1;
69962306a36Sopenharmony_ci			}
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci			printf(format,
70262306a36Sopenharmony_ci				rel->r_offset,
70362306a36Sopenharmony_ci				rel->r_info,
70462306a36Sopenharmony_ci				rel_type(ELF_R_TYPE(rel->r_info)),
70562306a36Sopenharmony_ci				sym->st_value,
70662306a36Sopenharmony_ci				name);
70762306a36Sopenharmony_ci		}
70862306a36Sopenharmony_ci	}
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	if (printed)
71162306a36Sopenharmony_ci		printf("\n");
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic void add_reloc(struct relocs *r, uint32_t offset)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	if (r->count == r->size) {
71762306a36Sopenharmony_ci		unsigned long newsize = r->size + 50000;
71862306a36Sopenharmony_ci		void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ci		if (!mem)
72162306a36Sopenharmony_ci			die("realloc of %ld entries for relocs failed\n",
72262306a36Sopenharmony_ci                                newsize);
72362306a36Sopenharmony_ci		r->offset = mem;
72462306a36Sopenharmony_ci		r->size = newsize;
72562306a36Sopenharmony_ci	}
72662306a36Sopenharmony_ci	r->offset[r->count++] = offset;
72762306a36Sopenharmony_ci}
72862306a36Sopenharmony_ci
72962306a36Sopenharmony_cistatic void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
73062306a36Sopenharmony_ci			Elf_Sym *sym, const char *symname))
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	int i;
73362306a36Sopenharmony_ci	/* Walk through the relocations */
73462306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
73562306a36Sopenharmony_ci		char *sym_strtab;
73662306a36Sopenharmony_ci		Elf_Sym *sh_symtab;
73762306a36Sopenharmony_ci		struct section *sec_applies, *sec_symtab;
73862306a36Sopenharmony_ci		int j;
73962306a36Sopenharmony_ci		struct section *sec = &secs[i];
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		if (sec->shdr.sh_type != SHT_REL_TYPE) {
74262306a36Sopenharmony_ci			continue;
74362306a36Sopenharmony_ci		}
74462306a36Sopenharmony_ci		sec_symtab  = sec->link;
74562306a36Sopenharmony_ci		sec_applies = &secs[sec->shdr.sh_info];
74662306a36Sopenharmony_ci		if (!(sec_applies->shdr.sh_flags & SHF_ALLOC)) {
74762306a36Sopenharmony_ci			continue;
74862306a36Sopenharmony_ci		}
74962306a36Sopenharmony_ci		sh_symtab = sec_symtab->symtab;
75062306a36Sopenharmony_ci		sym_strtab = sec_symtab->link->strtab;
75162306a36Sopenharmony_ci		for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
75262306a36Sopenharmony_ci			Elf_Rel *rel = &sec->reltab[j];
75362306a36Sopenharmony_ci			Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
75462306a36Sopenharmony_ci			const char *symname = sym_name(sym_strtab, sym);
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci			process(sec, rel, sym, symname);
75762306a36Sopenharmony_ci		}
75862306a36Sopenharmony_ci	}
75962306a36Sopenharmony_ci}
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci/*
76262306a36Sopenharmony_ci * The .data..percpu section is a special case for x86_64 SMP kernels.
76362306a36Sopenharmony_ci * It is used to initialize the actual per_cpu areas and to provide
76462306a36Sopenharmony_ci * definitions for the per_cpu variables that correspond to their offsets
76562306a36Sopenharmony_ci * within the percpu area. Since the values of all of the symbols need
76662306a36Sopenharmony_ci * to be offsets from the start of the per_cpu area the virtual address
76762306a36Sopenharmony_ci * (sh_addr) of .data..percpu is 0 in SMP kernels.
76862306a36Sopenharmony_ci *
76962306a36Sopenharmony_ci * This means that:
77062306a36Sopenharmony_ci *
77162306a36Sopenharmony_ci *	Relocations that reference symbols in the per_cpu area do not
77262306a36Sopenharmony_ci *	need further relocation (since the value is an offset relative
77362306a36Sopenharmony_ci *	to the start of the per_cpu area that does not change).
77462306a36Sopenharmony_ci *
77562306a36Sopenharmony_ci *	Relocations that apply to the per_cpu area need to have their
77662306a36Sopenharmony_ci *	offset adjusted by by the value of __per_cpu_load to make them
77762306a36Sopenharmony_ci *	point to the correct place in the loaded image (because the
77862306a36Sopenharmony_ci *	virtual address of .data..percpu is 0).
77962306a36Sopenharmony_ci *
78062306a36Sopenharmony_ci * For non SMP kernels .data..percpu is linked as part of the normal
78162306a36Sopenharmony_ci * kernel data and does not require special treatment.
78262306a36Sopenharmony_ci *
78362306a36Sopenharmony_ci */
78462306a36Sopenharmony_cistatic int per_cpu_shndx	= -1;
78562306a36Sopenharmony_cistatic Elf_Addr per_cpu_load_addr;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cistatic void percpu_init(void)
78862306a36Sopenharmony_ci{
78962306a36Sopenharmony_ci	int i;
79062306a36Sopenharmony_ci	for (i = 0; i < shnum; i++) {
79162306a36Sopenharmony_ci		ElfW(Sym) *sym;
79262306a36Sopenharmony_ci		if (strcmp(sec_name(i), ".data..percpu"))
79362306a36Sopenharmony_ci			continue;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci		if (secs[i].shdr.sh_addr != 0)	/* non SMP kernel */
79662306a36Sopenharmony_ci			return;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci		sym = sym_lookup("__per_cpu_load");
79962306a36Sopenharmony_ci		if (!sym)
80062306a36Sopenharmony_ci			die("can't find __per_cpu_load\n");
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci		per_cpu_shndx = i;
80362306a36Sopenharmony_ci		per_cpu_load_addr = sym->st_value;
80462306a36Sopenharmony_ci		return;
80562306a36Sopenharmony_ci	}
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci#if ELF_BITS == 64
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci/*
81162306a36Sopenharmony_ci * Check to see if a symbol lies in the .data..percpu section.
81262306a36Sopenharmony_ci *
81362306a36Sopenharmony_ci * The linker incorrectly associates some symbols with the
81462306a36Sopenharmony_ci * .data..percpu section so we also need to check the symbol
81562306a36Sopenharmony_ci * name to make sure that we classify the symbol correctly.
81662306a36Sopenharmony_ci *
81762306a36Sopenharmony_ci * The GNU linker incorrectly associates:
81862306a36Sopenharmony_ci *	__init_begin
81962306a36Sopenharmony_ci *	__per_cpu_load
82062306a36Sopenharmony_ci *
82162306a36Sopenharmony_ci * The "gold" linker incorrectly associates:
82262306a36Sopenharmony_ci *	init_per_cpu__fixed_percpu_data
82362306a36Sopenharmony_ci *	init_per_cpu__gdt_page
82462306a36Sopenharmony_ci */
82562306a36Sopenharmony_cistatic int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
82662306a36Sopenharmony_ci{
82762306a36Sopenharmony_ci	int shndx = sym_index(sym);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	return (shndx == per_cpu_shndx) &&
83062306a36Sopenharmony_ci		strcmp(symname, "__init_begin") &&
83162306a36Sopenharmony_ci		strcmp(symname, "__per_cpu_load") &&
83262306a36Sopenharmony_ci		strncmp(symname, "init_per_cpu_", 13);
83362306a36Sopenharmony_ci}
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_cistatic int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
83762306a36Sopenharmony_ci		      const char *symname)
83862306a36Sopenharmony_ci{
83962306a36Sopenharmony_ci	unsigned r_type = ELF64_R_TYPE(rel->r_info);
84062306a36Sopenharmony_ci	ElfW(Addr) offset = rel->r_offset;
84162306a36Sopenharmony_ci	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	if (sym->st_shndx == SHN_UNDEF)
84462306a36Sopenharmony_ci		return 0;
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	/*
84762306a36Sopenharmony_ci	 * Adjust the offset if this reloc applies to the percpu section.
84862306a36Sopenharmony_ci	 */
84962306a36Sopenharmony_ci	if (sec->shdr.sh_info == per_cpu_shndx)
85062306a36Sopenharmony_ci		offset += per_cpu_load_addr;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	switch (r_type) {
85362306a36Sopenharmony_ci	case R_X86_64_NONE:
85462306a36Sopenharmony_ci		/* NONE can be ignored. */
85562306a36Sopenharmony_ci		break;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	case R_X86_64_PC32:
85862306a36Sopenharmony_ci	case R_X86_64_PLT32:
85962306a36Sopenharmony_ci		/*
86062306a36Sopenharmony_ci		 * PC relative relocations don't need to be adjusted unless
86162306a36Sopenharmony_ci		 * referencing a percpu symbol.
86262306a36Sopenharmony_ci		 *
86362306a36Sopenharmony_ci		 * NB: R_X86_64_PLT32 can be treated as R_X86_64_PC32.
86462306a36Sopenharmony_ci		 */
86562306a36Sopenharmony_ci		if (is_percpu_sym(sym, symname))
86662306a36Sopenharmony_ci			add_reloc(&relocs32neg, offset);
86762306a36Sopenharmony_ci		break;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	case R_X86_64_PC64:
87062306a36Sopenharmony_ci		/*
87162306a36Sopenharmony_ci		 * Only used by jump labels
87262306a36Sopenharmony_ci		 */
87362306a36Sopenharmony_ci		if (is_percpu_sym(sym, symname))
87462306a36Sopenharmony_ci			die("Invalid R_X86_64_PC64 relocation against per-CPU symbol %s\n",
87562306a36Sopenharmony_ci			    symname);
87662306a36Sopenharmony_ci		break;
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_ci	case R_X86_64_32:
87962306a36Sopenharmony_ci	case R_X86_64_32S:
88062306a36Sopenharmony_ci	case R_X86_64_64:
88162306a36Sopenharmony_ci		/*
88262306a36Sopenharmony_ci		 * References to the percpu area don't need to be adjusted.
88362306a36Sopenharmony_ci		 */
88462306a36Sopenharmony_ci		if (is_percpu_sym(sym, symname))
88562306a36Sopenharmony_ci			break;
88662306a36Sopenharmony_ci
88762306a36Sopenharmony_ci		if (shn_abs) {
88862306a36Sopenharmony_ci			/*
88962306a36Sopenharmony_ci			 * Whitelisted absolute symbols do not require
89062306a36Sopenharmony_ci			 * relocation.
89162306a36Sopenharmony_ci			 */
89262306a36Sopenharmony_ci			if (is_reloc(S_ABS, symname))
89362306a36Sopenharmony_ci				break;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci			die("Invalid absolute %s relocation: %s\n",
89662306a36Sopenharmony_ci			    rel_type(r_type), symname);
89762306a36Sopenharmony_ci			break;
89862306a36Sopenharmony_ci		}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci		/*
90162306a36Sopenharmony_ci		 * Relocation offsets for 64 bit kernels are output
90262306a36Sopenharmony_ci		 * as 32 bits and sign extended back to 64 bits when
90362306a36Sopenharmony_ci		 * the relocations are processed.
90462306a36Sopenharmony_ci		 * Make sure that the offset will fit.
90562306a36Sopenharmony_ci		 */
90662306a36Sopenharmony_ci		if ((int32_t)offset != (int64_t)offset)
90762306a36Sopenharmony_ci			die("Relocation offset doesn't fit in 32 bits\n");
90862306a36Sopenharmony_ci
90962306a36Sopenharmony_ci		if (r_type == R_X86_64_64)
91062306a36Sopenharmony_ci			add_reloc(&relocs64, offset);
91162306a36Sopenharmony_ci		else
91262306a36Sopenharmony_ci			add_reloc(&relocs32, offset);
91362306a36Sopenharmony_ci		break;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	default:
91662306a36Sopenharmony_ci		die("Unsupported relocation type: %s (%d)\n",
91762306a36Sopenharmony_ci		    rel_type(r_type), r_type);
91862306a36Sopenharmony_ci		break;
91962306a36Sopenharmony_ci	}
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	return 0;
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci#else
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_cistatic int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
92762306a36Sopenharmony_ci		      const char *symname)
92862306a36Sopenharmony_ci{
92962306a36Sopenharmony_ci	unsigned r_type = ELF32_R_TYPE(rel->r_info);
93062306a36Sopenharmony_ci	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	switch (r_type) {
93362306a36Sopenharmony_ci	case R_386_NONE:
93462306a36Sopenharmony_ci	case R_386_PC32:
93562306a36Sopenharmony_ci	case R_386_PC16:
93662306a36Sopenharmony_ci	case R_386_PC8:
93762306a36Sopenharmony_ci	case R_386_PLT32:
93862306a36Sopenharmony_ci		/*
93962306a36Sopenharmony_ci		 * NONE can be ignored and PC relative relocations don't need
94062306a36Sopenharmony_ci		 * to be adjusted. Because sym must be defined, R_386_PLT32 can
94162306a36Sopenharmony_ci		 * be treated the same way as R_386_PC32.
94262306a36Sopenharmony_ci		 */
94362306a36Sopenharmony_ci		break;
94462306a36Sopenharmony_ci
94562306a36Sopenharmony_ci	case R_386_32:
94662306a36Sopenharmony_ci		if (shn_abs) {
94762306a36Sopenharmony_ci			/*
94862306a36Sopenharmony_ci			 * Whitelisted absolute symbols do not require
94962306a36Sopenharmony_ci			 * relocation.
95062306a36Sopenharmony_ci			 */
95162306a36Sopenharmony_ci			if (is_reloc(S_ABS, symname))
95262306a36Sopenharmony_ci				break;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci			die("Invalid absolute %s relocation: %s\n",
95562306a36Sopenharmony_ci			    rel_type(r_type), symname);
95662306a36Sopenharmony_ci			break;
95762306a36Sopenharmony_ci		}
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci		add_reloc(&relocs32, rel->r_offset);
96062306a36Sopenharmony_ci		break;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	default:
96362306a36Sopenharmony_ci		die("Unsupported relocation type: %s (%d)\n",
96462306a36Sopenharmony_ci		    rel_type(r_type), r_type);
96562306a36Sopenharmony_ci		break;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return 0;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cistatic int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
97262306a36Sopenharmony_ci			 const char *symname)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	unsigned r_type = ELF32_R_TYPE(rel->r_info);
97562306a36Sopenharmony_ci	int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	switch (r_type) {
97862306a36Sopenharmony_ci	case R_386_NONE:
97962306a36Sopenharmony_ci	case R_386_PC32:
98062306a36Sopenharmony_ci	case R_386_PC16:
98162306a36Sopenharmony_ci	case R_386_PC8:
98262306a36Sopenharmony_ci	case R_386_PLT32:
98362306a36Sopenharmony_ci		/*
98462306a36Sopenharmony_ci		 * NONE can be ignored and PC relative relocations don't need
98562306a36Sopenharmony_ci		 * to be adjusted. Because sym must be defined, R_386_PLT32 can
98662306a36Sopenharmony_ci		 * be treated the same way as R_386_PC32.
98762306a36Sopenharmony_ci		 */
98862306a36Sopenharmony_ci		break;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	case R_386_16:
99162306a36Sopenharmony_ci		if (shn_abs) {
99262306a36Sopenharmony_ci			/*
99362306a36Sopenharmony_ci			 * Whitelisted absolute symbols do not require
99462306a36Sopenharmony_ci			 * relocation.
99562306a36Sopenharmony_ci			 */
99662306a36Sopenharmony_ci			if (is_reloc(S_ABS, symname))
99762306a36Sopenharmony_ci				break;
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_ci			if (is_reloc(S_SEG, symname)) {
100062306a36Sopenharmony_ci				add_reloc(&relocs16, rel->r_offset);
100162306a36Sopenharmony_ci				break;
100262306a36Sopenharmony_ci			}
100362306a36Sopenharmony_ci		} else {
100462306a36Sopenharmony_ci			if (!is_reloc(S_LIN, symname))
100562306a36Sopenharmony_ci				break;
100662306a36Sopenharmony_ci		}
100762306a36Sopenharmony_ci		die("Invalid %s %s relocation: %s\n",
100862306a36Sopenharmony_ci		    shn_abs ? "absolute" : "relative",
100962306a36Sopenharmony_ci		    rel_type(r_type), symname);
101062306a36Sopenharmony_ci		break;
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	case R_386_32:
101362306a36Sopenharmony_ci		if (shn_abs) {
101462306a36Sopenharmony_ci			/*
101562306a36Sopenharmony_ci			 * Whitelisted absolute symbols do not require
101662306a36Sopenharmony_ci			 * relocation.
101762306a36Sopenharmony_ci			 */
101862306a36Sopenharmony_ci			if (is_reloc(S_ABS, symname))
101962306a36Sopenharmony_ci				break;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci			if (is_reloc(S_REL, symname)) {
102262306a36Sopenharmony_ci				add_reloc(&relocs32, rel->r_offset);
102362306a36Sopenharmony_ci				break;
102462306a36Sopenharmony_ci			}
102562306a36Sopenharmony_ci		} else {
102662306a36Sopenharmony_ci			if (is_reloc(S_LIN, symname))
102762306a36Sopenharmony_ci				add_reloc(&relocs32, rel->r_offset);
102862306a36Sopenharmony_ci			break;
102962306a36Sopenharmony_ci		}
103062306a36Sopenharmony_ci		die("Invalid %s %s relocation: %s\n",
103162306a36Sopenharmony_ci		    shn_abs ? "absolute" : "relative",
103262306a36Sopenharmony_ci		    rel_type(r_type), symname);
103362306a36Sopenharmony_ci		break;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	default:
103662306a36Sopenharmony_ci		die("Unsupported relocation type: %s (%d)\n",
103762306a36Sopenharmony_ci		    rel_type(r_type), r_type);
103862306a36Sopenharmony_ci		break;
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	return 0;
104262306a36Sopenharmony_ci}
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci#endif
104562306a36Sopenharmony_ci
104662306a36Sopenharmony_cistatic int cmp_relocs(const void *va, const void *vb)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	const uint32_t *a, *b;
104962306a36Sopenharmony_ci	a = va; b = vb;
105062306a36Sopenharmony_ci	return (*a == *b)? 0 : (*a > *b)? 1 : -1;
105162306a36Sopenharmony_ci}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_cistatic void sort_relocs(struct relocs *r)
105462306a36Sopenharmony_ci{
105562306a36Sopenharmony_ci	qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
105662306a36Sopenharmony_ci}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_cistatic int write32(uint32_t v, FILE *f)
105962306a36Sopenharmony_ci{
106062306a36Sopenharmony_ci	unsigned char buf[4];
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	put_unaligned_le32(v, buf);
106362306a36Sopenharmony_ci	return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
106462306a36Sopenharmony_ci}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_cistatic int write32_as_text(uint32_t v, FILE *f)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
106962306a36Sopenharmony_ci}
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic void emit_relocs(int as_text, int use_real_mode)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	int i;
107462306a36Sopenharmony_ci	int (*write_reloc)(uint32_t, FILE *) = write32;
107562306a36Sopenharmony_ci	int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
107662306a36Sopenharmony_ci			const char *symname);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci#if ELF_BITS == 64
107962306a36Sopenharmony_ci	if (!use_real_mode)
108062306a36Sopenharmony_ci		do_reloc = do_reloc64;
108162306a36Sopenharmony_ci	else
108262306a36Sopenharmony_ci		die("--realmode not valid for a 64-bit ELF file");
108362306a36Sopenharmony_ci#else
108462306a36Sopenharmony_ci	if (!use_real_mode)
108562306a36Sopenharmony_ci		do_reloc = do_reloc32;
108662306a36Sopenharmony_ci	else
108762306a36Sopenharmony_ci		do_reloc = do_reloc_real;
108862306a36Sopenharmony_ci#endif
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	/* Collect up the relocations */
109162306a36Sopenharmony_ci	walk_relocs(do_reloc);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	if (relocs16.count && !use_real_mode)
109462306a36Sopenharmony_ci		die("Segment relocations found but --realmode not specified\n");
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	/* Order the relocations for more efficient processing */
109762306a36Sopenharmony_ci	sort_relocs(&relocs32);
109862306a36Sopenharmony_ci#if ELF_BITS == 64
109962306a36Sopenharmony_ci	sort_relocs(&relocs32neg);
110062306a36Sopenharmony_ci	sort_relocs(&relocs64);
110162306a36Sopenharmony_ci#else
110262306a36Sopenharmony_ci	sort_relocs(&relocs16);
110362306a36Sopenharmony_ci#endif
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	/* Print the relocations */
110662306a36Sopenharmony_ci	if (as_text) {
110762306a36Sopenharmony_ci		/* Print the relocations in a form suitable that
110862306a36Sopenharmony_ci		 * gas will like.
110962306a36Sopenharmony_ci		 */
111062306a36Sopenharmony_ci		printf(".section \".data.reloc\",\"a\"\n");
111162306a36Sopenharmony_ci		printf(".balign 4\n");
111262306a36Sopenharmony_ci		write_reloc = write32_as_text;
111362306a36Sopenharmony_ci	}
111462306a36Sopenharmony_ci
111562306a36Sopenharmony_ci	if (use_real_mode) {
111662306a36Sopenharmony_ci		write_reloc(relocs16.count, stdout);
111762306a36Sopenharmony_ci		for (i = 0; i < relocs16.count; i++)
111862306a36Sopenharmony_ci			write_reloc(relocs16.offset[i], stdout);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci		write_reloc(relocs32.count, stdout);
112162306a36Sopenharmony_ci		for (i = 0; i < relocs32.count; i++)
112262306a36Sopenharmony_ci			write_reloc(relocs32.offset[i], stdout);
112362306a36Sopenharmony_ci	} else {
112462306a36Sopenharmony_ci#if ELF_BITS == 64
112562306a36Sopenharmony_ci		/* Print a stop */
112662306a36Sopenharmony_ci		write_reloc(0, stdout);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci		/* Now print each relocation */
112962306a36Sopenharmony_ci		for (i = 0; i < relocs64.count; i++)
113062306a36Sopenharmony_ci			write_reloc(relocs64.offset[i], stdout);
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci		/* Print a stop */
113362306a36Sopenharmony_ci		write_reloc(0, stdout);
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci		/* Now print each inverse 32-bit relocation */
113662306a36Sopenharmony_ci		for (i = 0; i < relocs32neg.count; i++)
113762306a36Sopenharmony_ci			write_reloc(relocs32neg.offset[i], stdout);
113862306a36Sopenharmony_ci#endif
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci		/* Print a stop */
114162306a36Sopenharmony_ci		write_reloc(0, stdout);
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci		/* Now print each relocation */
114462306a36Sopenharmony_ci		for (i = 0; i < relocs32.count; i++)
114562306a36Sopenharmony_ci			write_reloc(relocs32.offset[i], stdout);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci/*
115062306a36Sopenharmony_ci * As an aid to debugging problems with different linkers
115162306a36Sopenharmony_ci * print summary information about the relocs.
115262306a36Sopenharmony_ci * Since different linkers tend to emit the sections in
115362306a36Sopenharmony_ci * different orders we use the section names in the output.
115462306a36Sopenharmony_ci */
115562306a36Sopenharmony_cistatic int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
115662306a36Sopenharmony_ci				const char *symname)
115762306a36Sopenharmony_ci{
115862306a36Sopenharmony_ci	printf("%s\t%s\t%s\t%s\n",
115962306a36Sopenharmony_ci		sec_name(sec->shdr.sh_info),
116062306a36Sopenharmony_ci		rel_type(ELF_R_TYPE(rel->r_info)),
116162306a36Sopenharmony_ci		symname,
116262306a36Sopenharmony_ci		sec_name(sym_index(sym)));
116362306a36Sopenharmony_ci	return 0;
116462306a36Sopenharmony_ci}
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_cistatic void print_reloc_info(void)
116762306a36Sopenharmony_ci{
116862306a36Sopenharmony_ci	printf("reloc section\treloc type\tsymbol\tsymbol section\n");
116962306a36Sopenharmony_ci	walk_relocs(do_reloc_info);
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci#if ELF_BITS == 64
117362306a36Sopenharmony_ci# define process process_64
117462306a36Sopenharmony_ci#else
117562306a36Sopenharmony_ci# define process process_32
117662306a36Sopenharmony_ci#endif
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_civoid process(FILE *fp, int use_real_mode, int as_text,
117962306a36Sopenharmony_ci	     int show_absolute_syms, int show_absolute_relocs,
118062306a36Sopenharmony_ci	     int show_reloc_info)
118162306a36Sopenharmony_ci{
118262306a36Sopenharmony_ci	regex_init(use_real_mode);
118362306a36Sopenharmony_ci	read_ehdr(fp);
118462306a36Sopenharmony_ci	read_shdrs(fp);
118562306a36Sopenharmony_ci	read_strtabs(fp);
118662306a36Sopenharmony_ci	read_symtabs(fp);
118762306a36Sopenharmony_ci	read_relocs(fp);
118862306a36Sopenharmony_ci	if (ELF_BITS == 64)
118962306a36Sopenharmony_ci		percpu_init();
119062306a36Sopenharmony_ci	if (show_absolute_syms) {
119162306a36Sopenharmony_ci		print_absolute_symbols();
119262306a36Sopenharmony_ci		return;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci	if (show_absolute_relocs) {
119562306a36Sopenharmony_ci		print_absolute_relocs();
119662306a36Sopenharmony_ci		return;
119762306a36Sopenharmony_ci	}
119862306a36Sopenharmony_ci	if (show_reloc_info) {
119962306a36Sopenharmony_ci		print_reloc_info();
120062306a36Sopenharmony_ci		return;
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci	emit_relocs(as_text, use_real_mode);
120362306a36Sopenharmony_ci}
1204