aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 11:37:24 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-30 11:37:24 -0400
commit01c7cd0ef5d98fdd007d8a04c9f834bead6e5ee1 (patch)
tree6428c9dcaca3331456f1679afb97fc233655f93d
parent39b2f8656e2af4d5d490ce6e33e4ba229cda3e33 (diff)
parentc889ba801dc3b3a0155fa77d567f2c3a6097de1c (diff)
Merge branch 'x86-kaslr-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perparatory x86 kasrl changes from Ingo Molnar: "This contains changes from the ongoing KASLR work, by Kees Cook. The main changes are the use of a read-only IDT on x86 (which decouples the userspace visible virtual IDT address from the physical address), and a rework of ELF relocation support, in preparation of random, boot-time kernel image relocation." * 'x86-kaslr-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86, relocs: Refactor the relocs tool to merge 32- and 64-bit ELF x86, relocs: Build separate 32/64-bit tools x86, relocs: Add 64-bit ELF support to relocs tool x86, relocs: Consolidate processing logic x86, relocs: Generalize ELF structure names x86: Use a read-only IDT alias on all CPUs
-rw-r--r--arch/x86/include/asm/fixmap.h4
-rw-r--r--arch/x86/kernel/cpu/intel.c18
-rw-r--r--arch/x86/kernel/traps.c9
-rw-r--r--arch/x86/tools/Makefile1
-rw-r--r--arch/x86/tools/relocs.c783
-rw-r--r--arch/x86/tools/relocs.h36
-rw-r--r--arch/x86/tools/relocs_32.c17
-rw-r--r--arch/x86/tools/relocs_64.c17
-rw-r--r--arch/x86/tools/relocs_common.c76
-rw-r--r--arch/x86/xen/mmu.c4
10 files changed, 660 insertions, 305 deletions
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
index a09c28571064..51b9e322cb8f 100644
--- a/arch/x86/include/asm/fixmap.h
+++ b/arch/x86/include/asm/fixmap.h
@@ -104,9 +104,7 @@ enum fixed_addresses {
104 FIX_LI_PCIA, /* Lithium PCI Bridge A */ 104 FIX_LI_PCIA, /* Lithium PCI Bridge A */
105 FIX_LI_PCIB, /* Lithium PCI Bridge B */ 105 FIX_LI_PCIB, /* Lithium PCI Bridge B */
106#endif 106#endif
107#ifdef CONFIG_X86_F00F_BUG 107 FIX_RO_IDT, /* Virtual mapping for read-only IDT */
108 FIX_F00F_IDT, /* Virtual mapping for IDT */
109#endif
110#ifdef CONFIG_X86_CYCLONE_TIMER 108#ifdef CONFIG_X86_CYCLONE_TIMER
111 FIX_CYCLONE_TIMER, /*cyclone timer register*/ 109 FIX_CYCLONE_TIMER, /*cyclone timer register*/
112#endif 110#endif
diff --git a/arch/x86/kernel/cpu/intel.c b/arch/x86/kernel/cpu/intel.c
index a942b7c2ccee..9b0c441c03f5 100644
--- a/arch/x86/kernel/cpu/intel.c
+++ b/arch/x86/kernel/cpu/intel.c
@@ -176,20 +176,6 @@ int __cpuinit ppro_with_ram_bug(void)
176 return 0; 176 return 0;
177} 177}
178 178
179#ifdef CONFIG_X86_F00F_BUG
180static void __cpuinit trap_init_f00f_bug(void)
181{
182 __set_fixmap(FIX_F00F_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
183
184 /*
185 * Update the IDT descriptor and reload the IDT so that
186 * it uses the read-only mapped virtual address.
187 */
188 idt_descr.address = fix_to_virt(FIX_F00F_IDT);
189 load_idt(&idt_descr);
190}
191#endif
192
193static void __cpuinit intel_smp_check(struct cpuinfo_x86 *c) 179static void __cpuinit intel_smp_check(struct cpuinfo_x86 *c)
194{ 180{
195 /* calling is from identify_secondary_cpu() ? */ 181 /* calling is from identify_secondary_cpu() ? */
@@ -218,8 +204,7 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
218 /* 204 /*
219 * All current models of Pentium and Pentium with MMX technology CPUs 205 * All current models of Pentium and Pentium with MMX technology CPUs
220 * have the F0 0F bug, which lets nonprivileged users lock up the 206 * have the F0 0F bug, which lets nonprivileged users lock up the
221 * system. 207 * system. Announce that the fault handler will be checking for it.
222 * Note that the workaround only should be initialized once...
223 */ 208 */
224 clear_cpu_bug(c, X86_BUG_F00F); 209 clear_cpu_bug(c, X86_BUG_F00F);
225 if (!paravirt_enabled() && c->x86 == 5) { 210 if (!paravirt_enabled() && c->x86 == 5) {
@@ -227,7 +212,6 @@ static void __cpuinit intel_workarounds(struct cpuinfo_x86 *c)
227 212
228 set_cpu_bug(c, X86_BUG_F00F); 213 set_cpu_bug(c, X86_BUG_F00F);
229 if (!f00f_workaround_enabled) { 214 if (!f00f_workaround_enabled) {
230 trap_init_f00f_bug();
231 printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n"); 215 printk(KERN_NOTICE "Intel Pentium with F0 0F bug - workaround enabled.\n");
232 f00f_workaround_enabled = 1; 216 f00f_workaround_enabled = 1;
233 } 217 }
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index ff6d2271cbe2..772e2a846dec 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -56,6 +56,7 @@
56#include <asm/i387.h> 56#include <asm/i387.h>
57#include <asm/fpu-internal.h> 57#include <asm/fpu-internal.h>
58#include <asm/mce.h> 58#include <asm/mce.h>
59#include <asm/fixmap.h>
59#include <asm/mach_traps.h> 60#include <asm/mach_traps.h>
60 61
61#ifdef CONFIG_X86_64 62#ifdef CONFIG_X86_64
@@ -769,6 +770,14 @@ void __init trap_init(void)
769#endif 770#endif
770 771
771 /* 772 /*
773 * Set the IDT descriptor to a fixed read-only location, so that the
774 * "sidt" instruction will not leak the location of the kernel, and
775 * to defend the IDT against arbitrary memory write vulnerabilities.
776 * It will be reloaded in cpu_init() */
777 __set_fixmap(FIX_RO_IDT, __pa_symbol(idt_table), PAGE_KERNEL_RO);
778 idt_descr.address = fix_to_virt(FIX_RO_IDT);
779
780 /*
772 * Should be a barrier for any external CPU state: 781 * Should be a barrier for any external CPU state:
773 */ 782 */
774 cpu_init(); 783 cpu_init();
diff --git a/arch/x86/tools/Makefile b/arch/x86/tools/Makefile
index bae601f900ef..e8120346903b 100644
--- a/arch/x86/tools/Makefile
+++ b/arch/x86/tools/Makefile
@@ -39,4 +39,5 @@ $(obj)/insn_sanity.o: $(srctree)/arch/x86/lib/insn.c $(srctree)/arch/x86/lib/ina
39 39
40HOST_EXTRACFLAGS += -I$(srctree)/tools/include 40HOST_EXTRACFLAGS += -I$(srctree)/tools/include
41hostprogs-y += relocs 41hostprogs-y += relocs
42relocs-objs := relocs_32.o relocs_64.o relocs_common.o
42relocs: $(obj)/relocs 43relocs: $(obj)/relocs
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index 79d67bd507fa..590be1090892 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -1,43 +1,36 @@
1#include <stdio.h> 1/* This is included from relocs_32/64.c */
2#include <stdarg.h> 2
3#include <stdlib.h> 3#define ElfW(type) _ElfW(ELF_BITS, type)
4#include <stdint.h> 4#define _ElfW(bits, type) __ElfW(bits, type)
5#include <string.h> 5#define __ElfW(bits, type) Elf##bits##_##type
6#include <errno.h> 6
7#include <unistd.h> 7#define Elf_Addr ElfW(Addr)
8#include <elf.h> 8#define Elf_Ehdr ElfW(Ehdr)
9#include <byteswap.h> 9#define Elf_Phdr ElfW(Phdr)
10#define USE_BSD 10#define Elf_Shdr ElfW(Shdr)
11#include <endian.h> 11#define Elf_Sym ElfW(Sym)
12#include <regex.h> 12
13#include <tools/le_byteshift.h> 13static Elf_Ehdr ehdr;
14 14
15static void die(char *fmt, ...); 15struct relocs {
16 16 uint32_t *offset;
17#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) 17 unsigned long count;
18static Elf32_Ehdr ehdr; 18 unsigned long size;
19static unsigned long reloc_count, reloc_idx; 19};
20static unsigned long *relocs; 20
21static unsigned long reloc16_count, reloc16_idx; 21static struct relocs relocs16;
22static unsigned long *relocs16; 22static struct relocs relocs32;
23static struct relocs relocs64;
23 24
24struct section { 25struct section {
25 Elf32_Shdr shdr; 26 Elf_Shdr shdr;
26 struct section *link; 27 struct section *link;
27 Elf32_Sym *symtab; 28 Elf_Sym *symtab;
28 Elf32_Rel *reltab; 29 Elf_Rel *reltab;
29 char *strtab; 30 char *strtab;
30}; 31};
31static struct section *secs; 32static struct section *secs;
32 33
33enum symtype {
34 S_ABS,
35 S_REL,
36 S_SEG,
37 S_LIN,
38 S_NSYMTYPES
39};
40
41static const char * const sym_regex_kernel[S_NSYMTYPES] = { 34static const char * const sym_regex_kernel[S_NSYMTYPES] = {
42/* 35/*
43 * Following symbols have been audited. There values are constant and do 36 * Following symbols have been audited. There values are constant and do
@@ -49,6 +42,9 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
49 "^(xen_irq_disable_direct_reloc$|" 42 "^(xen_irq_disable_direct_reloc$|"
50 "xen_save_fl_direct_reloc$|" 43 "xen_save_fl_direct_reloc$|"
51 "VDSO|" 44 "VDSO|"
45#if ELF_BITS == 64
46 "__vvar_page|"
47#endif
52 "__crc_)", 48 "__crc_)",
53 49
54/* 50/*
@@ -72,6 +68,11 @@ static const char * const sym_regex_kernel[S_NSYMTYPES] = {
72 "__end_rodata|" 68 "__end_rodata|"
73 "__initramfs_start|" 69 "__initramfs_start|"
74 "(jiffies|jiffies_64)|" 70 "(jiffies|jiffies_64)|"
71#if ELF_BITS == 64
72 "__per_cpu_load|"
73 "init_per_cpu__.*|"
74 "__end_rodata_hpage_align|"
75#endif
75 "_end)$" 76 "_end)$"
76}; 77};
77 78
@@ -132,15 +133,6 @@ static void regex_init(int use_real_mode)
132 } 133 }
133} 134}
134 135
135static void die(char *fmt, ...)
136{
137 va_list ap;
138 va_start(ap, fmt);
139 vfprintf(stderr, fmt, ap);
140 va_end(ap);
141 exit(1);
142}
143
144static const char *sym_type(unsigned type) 136static const char *sym_type(unsigned type)
145{ 137{
146 static const char *type_name[] = { 138 static const char *type_name[] = {
@@ -198,6 +190,24 @@ static const char *rel_type(unsigned type)
198{ 190{
199 static const char *type_name[] = { 191 static const char *type_name[] = {
200#define REL_TYPE(X) [X] = #X 192#define REL_TYPE(X) [X] = #X
193#if ELF_BITS == 64
194 REL_TYPE(R_X86_64_NONE),
195 REL_TYPE(R_X86_64_64),
196 REL_TYPE(R_X86_64_PC32),
197 REL_TYPE(R_X86_64_GOT32),
198 REL_TYPE(R_X86_64_PLT32),
199 REL_TYPE(R_X86_64_COPY),
200 REL_TYPE(R_X86_64_GLOB_DAT),
201 REL_TYPE(R_X86_64_JUMP_SLOT),
202 REL_TYPE(R_X86_64_RELATIVE),
203 REL_TYPE(R_X86_64_GOTPCREL),
204 REL_TYPE(R_X86_64_32),
205 REL_TYPE(R_X86_64_32S),
206 REL_TYPE(R_X86_64_16),
207 REL_TYPE(R_X86_64_PC16),
208 REL_TYPE(R_X86_64_8),
209 REL_TYPE(R_X86_64_PC8),
210#else
201 REL_TYPE(R_386_NONE), 211 REL_TYPE(R_386_NONE),
202 REL_TYPE(R_386_32), 212 REL_TYPE(R_386_32),
203 REL_TYPE(R_386_PC32), 213 REL_TYPE(R_386_PC32),
@@ -213,6 +223,7 @@ static const char *rel_type(unsigned type)
213 REL_TYPE(R_386_PC8), 223 REL_TYPE(R_386_PC8),
214 REL_TYPE(R_386_16), 224 REL_TYPE(R_386_16),
215 REL_TYPE(R_386_PC16), 225 REL_TYPE(R_386_PC16),
226#endif
216#undef REL_TYPE 227#undef REL_TYPE
217 }; 228 };
218 const char *name = "unknown type rel type name"; 229 const char *name = "unknown type rel type name";
@@ -240,7 +251,7 @@ static const char *sec_name(unsigned shndx)
240 return name; 251 return name;
241} 252}
242 253
243static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) 254static const char *sym_name(const char *sym_strtab, Elf_Sym *sym)
244{ 255{
245 const char *name; 256 const char *name;
246 name = "<noname>"; 257 name = "<noname>";
@@ -253,15 +264,42 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym)
253 return name; 264 return name;
254} 265}
255 266
267static Elf_Sym *sym_lookup(const char *symname)
268{
269 int i;
270 for (i = 0; i < ehdr.e_shnum; i++) {
271 struct section *sec = &secs[i];
272 long nsyms;
273 char *strtab;
274 Elf_Sym *symtab;
275 Elf_Sym *sym;
276
277 if (sec->shdr.sh_type != SHT_SYMTAB)
278 continue;
256 279
280 nsyms = sec->shdr.sh_size/sizeof(Elf_Sym);
281 symtab = sec->symtab;
282 strtab = sec->link->strtab;
283
284 for (sym = symtab; --nsyms >= 0; sym++) {
285 if (!sym->st_name)
286 continue;
287 if (strcmp(symname, strtab + sym->st_name) == 0)
288 return sym;
289 }
290 }
291 return 0;
292}
257 293
258#if BYTE_ORDER == LITTLE_ENDIAN 294#if BYTE_ORDER == LITTLE_ENDIAN
259#define le16_to_cpu(val) (val) 295#define le16_to_cpu(val) (val)
260#define le32_to_cpu(val) (val) 296#define le32_to_cpu(val) (val)
297#define le64_to_cpu(val) (val)
261#endif 298#endif
262#if BYTE_ORDER == BIG_ENDIAN 299#if BYTE_ORDER == BIG_ENDIAN
263#define le16_to_cpu(val) bswap_16(val) 300#define le16_to_cpu(val) bswap_16(val)
264#define le32_to_cpu(val) bswap_32(val) 301#define le32_to_cpu(val) bswap_32(val)
302#define le64_to_cpu(val) bswap_64(val)
265#endif 303#endif
266 304
267static uint16_t elf16_to_cpu(uint16_t val) 305static uint16_t elf16_to_cpu(uint16_t val)
@@ -274,6 +312,23 @@ static uint32_t elf32_to_cpu(uint32_t val)
274 return le32_to_cpu(val); 312 return le32_to_cpu(val);
275} 313}
276 314
315#define elf_half_to_cpu(x) elf16_to_cpu(x)
316#define elf_word_to_cpu(x) elf32_to_cpu(x)
317
318#if ELF_BITS == 64
319static uint64_t elf64_to_cpu(uint64_t val)
320{
321 return le64_to_cpu(val);
322}
323#define elf_addr_to_cpu(x) elf64_to_cpu(x)
324#define elf_off_to_cpu(x) elf64_to_cpu(x)
325#define elf_xword_to_cpu(x) elf64_to_cpu(x)
326#else
327#define elf_addr_to_cpu(x) elf32_to_cpu(x)
328#define elf_off_to_cpu(x) elf32_to_cpu(x)
329#define elf_xword_to_cpu(x) elf32_to_cpu(x)
330#endif
331
277static void read_ehdr(FILE *fp) 332static void read_ehdr(FILE *fp)
278{ 333{
279 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) { 334 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
@@ -283,8 +338,8 @@ static void read_ehdr(FILE *fp)
283 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) { 338 if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0) {
284 die("No ELF magic\n"); 339 die("No ELF magic\n");
285 } 340 }
286 if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) { 341 if (ehdr.e_ident[EI_CLASS] != ELF_CLASS) {
287 die("Not a 32 bit executable\n"); 342 die("Not a %d bit executable\n", ELF_BITS);
288 } 343 }
289 if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) { 344 if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB) {
290 die("Not a LSB ELF executable\n"); 345 die("Not a LSB ELF executable\n");
@@ -293,36 +348,36 @@ static void read_ehdr(FILE *fp)
293 die("Unknown ELF version\n"); 348 die("Unknown ELF version\n");
294 } 349 }
295 /* Convert the fields to native endian */ 350 /* Convert the fields to native endian */
296 ehdr.e_type = elf16_to_cpu(ehdr.e_type); 351 ehdr.e_type = elf_half_to_cpu(ehdr.e_type);
297 ehdr.e_machine = elf16_to_cpu(ehdr.e_machine); 352 ehdr.e_machine = elf_half_to_cpu(ehdr.e_machine);
298 ehdr.e_version = elf32_to_cpu(ehdr.e_version); 353 ehdr.e_version = elf_word_to_cpu(ehdr.e_version);
299 ehdr.e_entry = elf32_to_cpu(ehdr.e_entry); 354 ehdr.e_entry = elf_addr_to_cpu(ehdr.e_entry);
300 ehdr.e_phoff = elf32_to_cpu(ehdr.e_phoff); 355 ehdr.e_phoff = elf_off_to_cpu(ehdr.e_phoff);
301 ehdr.e_shoff = elf32_to_cpu(ehdr.e_shoff); 356 ehdr.e_shoff = elf_off_to_cpu(ehdr.e_shoff);
302 ehdr.e_flags = elf32_to_cpu(ehdr.e_flags); 357 ehdr.e_flags = elf_word_to_cpu(ehdr.e_flags);
303 ehdr.e_ehsize = elf16_to_cpu(ehdr.e_ehsize); 358 ehdr.e_ehsize = elf_half_to_cpu(ehdr.e_ehsize);
304 ehdr.e_phentsize = elf16_to_cpu(ehdr.e_phentsize); 359 ehdr.e_phentsize = elf_half_to_cpu(ehdr.e_phentsize);
305 ehdr.e_phnum = elf16_to_cpu(ehdr.e_phnum); 360 ehdr.e_phnum = elf_half_to_cpu(ehdr.e_phnum);
306 ehdr.e_shentsize = elf16_to_cpu(ehdr.e_shentsize); 361 ehdr.e_shentsize = elf_half_to_cpu(ehdr.e_shentsize);
307 ehdr.e_shnum = elf16_to_cpu(ehdr.e_shnum); 362 ehdr.e_shnum = elf_half_to_cpu(ehdr.e_shnum);
308 ehdr.e_shstrndx = elf16_to_cpu(ehdr.e_shstrndx); 363 ehdr.e_shstrndx = elf_half_to_cpu(ehdr.e_shstrndx);
309 364
310 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) { 365 if ((ehdr.e_type != ET_EXEC) && (ehdr.e_type != ET_DYN)) {
311 die("Unsupported ELF header type\n"); 366 die("Unsupported ELF header type\n");
312 } 367 }
313 if (ehdr.e_machine != EM_386) { 368 if (ehdr.e_machine != ELF_MACHINE) {
314 die("Not for x86\n"); 369 die("Not for %s\n", ELF_MACHINE_NAME);
315 } 370 }
316 if (ehdr.e_version != EV_CURRENT) { 371 if (ehdr.e_version != EV_CURRENT) {
317 die("Unknown ELF version\n"); 372 die("Unknown ELF version\n");
318 } 373 }
319 if (ehdr.e_ehsize != sizeof(Elf32_Ehdr)) { 374 if (ehdr.e_ehsize != sizeof(Elf_Ehdr)) {
320 die("Bad Elf header size\n"); 375 die("Bad Elf header size\n");
321 } 376 }
322 if (ehdr.e_phentsize != sizeof(Elf32_Phdr)) { 377 if (ehdr.e_phentsize != sizeof(Elf_Phdr)) {
323 die("Bad program header entry\n"); 378 die("Bad program header entry\n");
324 } 379 }
325 if (ehdr.e_shentsize != sizeof(Elf32_Shdr)) { 380 if (ehdr.e_shentsize != sizeof(Elf_Shdr)) {
326 die("Bad section header entry\n"); 381 die("Bad section header entry\n");
327 } 382 }
328 if (ehdr.e_shstrndx >= ehdr.e_shnum) { 383 if (ehdr.e_shstrndx >= ehdr.e_shnum) {
@@ -333,7 +388,7 @@ static void read_ehdr(FILE *fp)
333static void read_shdrs(FILE *fp) 388static void read_shdrs(FILE *fp)
334{ 389{
335 int i; 390 int i;
336 Elf32_Shdr shdr; 391 Elf_Shdr shdr;
337 392
338 secs = calloc(ehdr.e_shnum, sizeof(struct section)); 393 secs = calloc(ehdr.e_shnum, sizeof(struct section));
339 if (!secs) { 394 if (!secs) {
@@ -349,16 +404,16 @@ static void read_shdrs(FILE *fp)
349 if (fread(&shdr, sizeof shdr, 1, fp) != 1) 404 if (fread(&shdr, sizeof shdr, 1, fp) != 1)
350 die("Cannot read ELF section headers %d/%d: %s\n", 405 die("Cannot read ELF section headers %d/%d: %s\n",
351 i, ehdr.e_shnum, strerror(errno)); 406 i, ehdr.e_shnum, strerror(errno));
352 sec->shdr.sh_name = elf32_to_cpu(shdr.sh_name); 407 sec->shdr.sh_name = elf_word_to_cpu(shdr.sh_name);
353 sec->shdr.sh_type = elf32_to_cpu(shdr.sh_type); 408 sec->shdr.sh_type = elf_word_to_cpu(shdr.sh_type);
354 sec->shdr.sh_flags = elf32_to_cpu(shdr.sh_flags); 409 sec->shdr.sh_flags = elf_xword_to_cpu(shdr.sh_flags);
355 sec->shdr.sh_addr = elf32_to_cpu(shdr.sh_addr); 410 sec->shdr.sh_addr = elf_addr_to_cpu(shdr.sh_addr);
356 sec->shdr.sh_offset = elf32_to_cpu(shdr.sh_offset); 411 sec->shdr.sh_offset = elf_off_to_cpu(shdr.sh_offset);
357 sec->shdr.sh_size = elf32_to_cpu(shdr.sh_size); 412 sec->shdr.sh_size = elf_xword_to_cpu(shdr.sh_size);
358 sec->shdr.sh_link = elf32_to_cpu(shdr.sh_link); 413 sec->shdr.sh_link = elf_word_to_cpu(shdr.sh_link);
359 sec->shdr.sh_info = elf32_to_cpu(shdr.sh_info); 414 sec->shdr.sh_info = elf_word_to_cpu(shdr.sh_info);
360 sec->shdr.sh_addralign = elf32_to_cpu(shdr.sh_addralign); 415 sec->shdr.sh_addralign = elf_xword_to_cpu(shdr.sh_addralign);
361 sec->shdr.sh_entsize = elf32_to_cpu(shdr.sh_entsize); 416 sec->shdr.sh_entsize = elf_xword_to_cpu(shdr.sh_entsize);
362 if (sec->shdr.sh_link < ehdr.e_shnum) 417 if (sec->shdr.sh_link < ehdr.e_shnum)
363 sec->link = &secs[sec->shdr.sh_link]; 418 sec->link = &secs[sec->shdr.sh_link];
364 } 419 }
@@ -412,12 +467,12 @@ static void read_symtabs(FILE *fp)
412 die("Cannot read symbol table: %s\n", 467 die("Cannot read symbol table: %s\n",
413 strerror(errno)); 468 strerror(errno));
414 } 469 }
415 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { 470 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
416 Elf32_Sym *sym = &sec->symtab[j]; 471 Elf_Sym *sym = &sec->symtab[j];
417 sym->st_name = elf32_to_cpu(sym->st_name); 472 sym->st_name = elf_word_to_cpu(sym->st_name);
418 sym->st_value = elf32_to_cpu(sym->st_value); 473 sym->st_value = elf_addr_to_cpu(sym->st_value);
419 sym->st_size = elf32_to_cpu(sym->st_size); 474 sym->st_size = elf_xword_to_cpu(sym->st_size);
420 sym->st_shndx = elf16_to_cpu(sym->st_shndx); 475 sym->st_shndx = elf_half_to_cpu(sym->st_shndx);
421 } 476 }
422 } 477 }
423} 478}
@@ -428,7 +483,7 @@ static void read_relocs(FILE *fp)
428 int i,j; 483 int i,j;
429 for (i = 0; i < ehdr.e_shnum; i++) { 484 for (i = 0; i < ehdr.e_shnum; i++) {
430 struct section *sec = &secs[i]; 485 struct section *sec = &secs[i];
431 if (sec->shdr.sh_type != SHT_REL) { 486 if (sec->shdr.sh_type != SHT_REL_TYPE) {
432 continue; 487 continue;
433 } 488 }
434 sec->reltab = malloc(sec->shdr.sh_size); 489 sec->reltab = malloc(sec->shdr.sh_size);
@@ -445,10 +500,13 @@ static void read_relocs(FILE *fp)
445 die("Cannot read symbol table: %s\n", 500 die("Cannot read symbol table: %s\n",
446 strerror(errno)); 501 strerror(errno));
447 } 502 }
448 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 503 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
449 Elf32_Rel *rel = &sec->reltab[j]; 504 Elf_Rel *rel = &sec->reltab[j];
450 rel->r_offset = elf32_to_cpu(rel->r_offset); 505 rel->r_offset = elf_addr_to_cpu(rel->r_offset);
451 rel->r_info = elf32_to_cpu(rel->r_info); 506 rel->r_info = elf_xword_to_cpu(rel->r_info);
507#if (SHT_REL_TYPE == SHT_RELA)
508 rel->r_addend = elf_xword_to_cpu(rel->r_addend);
509#endif
452 } 510 }
453 } 511 }
454} 512}
@@ -457,6 +515,13 @@ static void read_relocs(FILE *fp)
457static void print_absolute_symbols(void) 515static void print_absolute_symbols(void)
458{ 516{
459 int i; 517 int i;
518 const char *format;
519
520 if (ELF_BITS == 64)
521 format = "%5d %016"PRIx64" %5"PRId64" %10s %10s %12s %s\n";
522 else
523 format = "%5d %08"PRIx32" %5"PRId32" %10s %10s %12s %s\n";
524
460 printf("Absolute symbols\n"); 525 printf("Absolute symbols\n");
461 printf(" Num: Value Size Type Bind Visibility Name\n"); 526 printf(" Num: Value Size Type Bind Visibility Name\n");
462 for (i = 0; i < ehdr.e_shnum; i++) { 527 for (i = 0; i < ehdr.e_shnum; i++) {
@@ -468,19 +533,19 @@ static void print_absolute_symbols(void)
468 continue; 533 continue;
469 } 534 }
470 sym_strtab = sec->link->strtab; 535 sym_strtab = sec->link->strtab;
471 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Sym); j++) { 536 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Sym); j++) {
472 Elf32_Sym *sym; 537 Elf_Sym *sym;
473 const char *name; 538 const char *name;
474 sym = &sec->symtab[j]; 539 sym = &sec->symtab[j];
475 name = sym_name(sym_strtab, sym); 540 name = sym_name(sym_strtab, sym);
476 if (sym->st_shndx != SHN_ABS) { 541 if (sym->st_shndx != SHN_ABS) {
477 continue; 542 continue;
478 } 543 }
479 printf("%5d %08x %5d %10s %10s %12s %s\n", 544 printf(format,
480 j, sym->st_value, sym->st_size, 545 j, sym->st_value, sym->st_size,
481 sym_type(ELF32_ST_TYPE(sym->st_info)), 546 sym_type(ELF_ST_TYPE(sym->st_info)),
482 sym_bind(ELF32_ST_BIND(sym->st_info)), 547 sym_bind(ELF_ST_BIND(sym->st_info)),
483 sym_visibility(ELF32_ST_VISIBILITY(sym->st_other)), 548 sym_visibility(ELF_ST_VISIBILITY(sym->st_other)),
484 name); 549 name);
485 } 550 }
486 } 551 }
@@ -490,14 +555,20 @@ static void print_absolute_symbols(void)
490static void print_absolute_relocs(void) 555static void print_absolute_relocs(void)
491{ 556{
492 int i, printed = 0; 557 int i, printed = 0;
558 const char *format;
559
560 if (ELF_BITS == 64)
561 format = "%016"PRIx64" %016"PRIx64" %10s %016"PRIx64" %s\n";
562 else
563 format = "%08"PRIx32" %08"PRIx32" %10s %08"PRIx32" %s\n";
493 564
494 for (i = 0; i < ehdr.e_shnum; i++) { 565 for (i = 0; i < ehdr.e_shnum; i++) {
495 struct section *sec = &secs[i]; 566 struct section *sec = &secs[i];
496 struct section *sec_applies, *sec_symtab; 567 struct section *sec_applies, *sec_symtab;
497 char *sym_strtab; 568 char *sym_strtab;
498 Elf32_Sym *sh_symtab; 569 Elf_Sym *sh_symtab;
499 int j; 570 int j;
500 if (sec->shdr.sh_type != SHT_REL) { 571 if (sec->shdr.sh_type != SHT_REL_TYPE) {
501 continue; 572 continue;
502 } 573 }
503 sec_symtab = sec->link; 574 sec_symtab = sec->link;
@@ -507,12 +578,12 @@ static void print_absolute_relocs(void)
507 } 578 }
508 sh_symtab = sec_symtab->symtab; 579 sh_symtab = sec_symtab->symtab;
509 sym_strtab = sec_symtab->link->strtab; 580 sym_strtab = sec_symtab->link->strtab;
510 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 581 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
511 Elf32_Rel *rel; 582 Elf_Rel *rel;
512 Elf32_Sym *sym; 583 Elf_Sym *sym;
513 const char *name; 584 const char *name;
514 rel = &sec->reltab[j]; 585 rel = &sec->reltab[j];
515 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; 586 sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
516 name = sym_name(sym_strtab, sym); 587 name = sym_name(sym_strtab, sym);
517 if (sym->st_shndx != SHN_ABS) { 588 if (sym->st_shndx != SHN_ABS) {
518 continue; 589 continue;
@@ -542,10 +613,10 @@ static void print_absolute_relocs(void)
542 printed = 1; 613 printed = 1;
543 } 614 }
544 615
545 printf("%08x %08x %10s %08x %s\n", 616 printf(format,
546 rel->r_offset, 617 rel->r_offset,
547 rel->r_info, 618 rel->r_info,
548 rel_type(ELF32_R_TYPE(rel->r_info)), 619 rel_type(ELF_R_TYPE(rel->r_info)),
549 sym->st_value, 620 sym->st_value,
550 name); 621 name);
551 } 622 }
@@ -555,19 +626,34 @@ static void print_absolute_relocs(void)
555 printf("\n"); 626 printf("\n");
556} 627}
557 628
558static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym), 629static void add_reloc(struct relocs *r, uint32_t offset)
559 int use_real_mode) 630{
631 if (r->count == r->size) {
632 unsigned long newsize = r->size + 50000;
633 void *mem = realloc(r->offset, newsize * sizeof(r->offset[0]));
634
635 if (!mem)
636 die("realloc of %ld entries for relocs failed\n",
637 newsize);
638 r->offset = mem;
639 r->size = newsize;
640 }
641 r->offset[r->count++] = offset;
642}
643
644static void walk_relocs(int (*process)(struct section *sec, Elf_Rel *rel,
645 Elf_Sym *sym, const char *symname))
560{ 646{
561 int i; 647 int i;
562 /* Walk through the relocations */ 648 /* Walk through the relocations */
563 for (i = 0; i < ehdr.e_shnum; i++) { 649 for (i = 0; i < ehdr.e_shnum; i++) {
564 char *sym_strtab; 650 char *sym_strtab;
565 Elf32_Sym *sh_symtab; 651 Elf_Sym *sh_symtab;
566 struct section *sec_applies, *sec_symtab; 652 struct section *sec_applies, *sec_symtab;
567 int j; 653 int j;
568 struct section *sec = &secs[i]; 654 struct section *sec = &secs[i];
569 655
570 if (sec->shdr.sh_type != SHT_REL) { 656 if (sec->shdr.sh_type != SHT_REL_TYPE) {
571 continue; 657 continue;
572 } 658 }
573 sec_symtab = sec->link; 659 sec_symtab = sec->link;
@@ -577,101 +663,281 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym),
577 } 663 }
578 sh_symtab = sec_symtab->symtab; 664 sh_symtab = sec_symtab->symtab;
579 sym_strtab = sec_symtab->link->strtab; 665 sym_strtab = sec_symtab->link->strtab;
580 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { 666 for (j = 0; j < sec->shdr.sh_size/sizeof(Elf_Rel); j++) {
581 Elf32_Rel *rel; 667 Elf_Rel *rel = &sec->reltab[j];
582 Elf32_Sym *sym; 668 Elf_Sym *sym = &sh_symtab[ELF_R_SYM(rel->r_info)];
583 unsigned r_type; 669 const char *symname = sym_name(sym_strtab, sym);
584 const char *symname;
585 int shn_abs;
586 670
587 rel = &sec->reltab[j]; 671 process(sec, rel, sym, symname);
588 sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; 672 }
589 r_type = ELF32_R_TYPE(rel->r_info); 673 }
590 674}
591 shn_abs = sym->st_shndx == SHN_ABS;
592
593 switch (r_type) {
594 case R_386_NONE:
595 case R_386_PC32:
596 case R_386_PC16:
597 case R_386_PC8:
598 /*
599 * NONE can be ignored and and PC relative
600 * relocations don't need to be adjusted.
601 */
602 break;
603 675
604 case R_386_16: 676/*
605 symname = sym_name(sym_strtab, sym); 677 * The .data..percpu section is a special case for x86_64 SMP kernels.
606 if (!use_real_mode) 678 * It is used to initialize the actual per_cpu areas and to provide
607 goto bad; 679 * definitions for the per_cpu variables that correspond to their offsets
608 if (shn_abs) { 680 * within the percpu area. Since the values of all of the symbols need
609 if (is_reloc(S_ABS, symname)) 681 * to be offsets from the start of the per_cpu area the virtual address
610 break; 682 * (sh_addr) of .data..percpu is 0 in SMP kernels.
611 else if (!is_reloc(S_SEG, symname)) 683 *
612 goto bad; 684 * This means that:
613 } else { 685 *
614 if (is_reloc(S_LIN, symname)) 686 * Relocations that reference symbols in the per_cpu area do not
615 goto bad; 687 * need further relocation (since the value is an offset relative
616 else 688 * to the start of the per_cpu area that does not change).
617 break; 689 *
618 } 690 * Relocations that apply to the per_cpu area need to have their
619 visit(rel, sym); 691 * offset adjusted by by the value of __per_cpu_load to make them
620 break; 692 * point to the correct place in the loaded image (because the
693 * virtual address of .data..percpu is 0).
694 *
695 * For non SMP kernels .data..percpu is linked as part of the normal
696 * kernel data and does not require special treatment.
697 *
698 */
699static int per_cpu_shndx = -1;
700Elf_Addr per_cpu_load_addr;
621 701
622 case R_386_32: 702static void percpu_init(void)
623 symname = sym_name(sym_strtab, sym); 703{
624 if (shn_abs) { 704 int i;
625 if (is_reloc(S_ABS, symname)) 705 for (i = 0; i < ehdr.e_shnum; i++) {
626 break; 706 ElfW(Sym) *sym;
627 else if (!is_reloc(S_REL, symname)) 707 if (strcmp(sec_name(i), ".data..percpu"))
628 goto bad; 708 continue;
629 } else { 709
630 if (use_real_mode && 710 if (secs[i].shdr.sh_addr != 0) /* non SMP kernel */
631 !is_reloc(S_LIN, symname)) 711 return;
632 break; 712
633 } 713 sym = sym_lookup("__per_cpu_load");
634 visit(rel, sym); 714 if (!sym)
635 break; 715 die("can't find __per_cpu_load\n");
636 default: 716
637 die("Unsupported relocation type: %s (%d)\n", 717 per_cpu_shndx = i;
638 rel_type(r_type), r_type); 718 per_cpu_load_addr = sym->st_value;
719 return;
720 }
721}
722
723#if ELF_BITS == 64
724
725/*
726 * Check to see if a symbol lies in the .data..percpu section.
727 * For some as yet not understood reason the "__init_begin"
728 * symbol which immediately preceeds the .data..percpu section
729 * also shows up as it it were part of it so we do an explict
730 * check for that symbol name and ignore it.
731 */
732static int is_percpu_sym(ElfW(Sym) *sym, const char *symname)
733{
734 return (sym->st_shndx == per_cpu_shndx) &&
735 strcmp(symname, "__init_begin");
736}
737
738
739static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
740 const char *symname)
741{
742 unsigned r_type = ELF64_R_TYPE(rel->r_info);
743 ElfW(Addr) offset = rel->r_offset;
744 int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
745
746 if (sym->st_shndx == SHN_UNDEF)
747 return 0;
748
749 /*
750 * Adjust the offset if this reloc applies to the percpu section.
751 */
752 if (sec->shdr.sh_info == per_cpu_shndx)
753 offset += per_cpu_load_addr;
754
755 switch (r_type) {
756 case R_X86_64_NONE:
757 case R_X86_64_PC32:
758 /*
759 * NONE can be ignored and PC relative relocations don't
760 * need to be adjusted.
761 */
762 break;
763
764 case R_X86_64_32:
765 case R_X86_64_32S:
766 case R_X86_64_64:
767 /*
768 * References to the percpu area don't need to be adjusted.
769 */
770 if (is_percpu_sym(sym, symname))
771 break;
772
773 if (shn_abs) {
774 /*
775 * Whitelisted absolute symbols do not require
776 * relocation.
777 */
778 if (is_reloc(S_ABS, symname))
639 break; 779 break;
640 bad: 780
641 symname = sym_name(sym_strtab, sym); 781 die("Invalid absolute %s relocation: %s\n",
642 die("Invalid %s %s relocation: %s\n", 782 rel_type(r_type), symname);
643 shn_abs ? "absolute" : "relative", 783 break;
644 rel_type(r_type), symname);
645 }
646 } 784 }
785
786 /*
787 * Relocation offsets for 64 bit kernels are output
788 * as 32 bits and sign extended back to 64 bits when
789 * the relocations are processed.
790 * Make sure that the offset will fit.
791 */
792 if ((int32_t)offset != (int64_t)offset)
793 die("Relocation offset doesn't fit in 32 bits\n");
794
795 if (r_type == R_X86_64_64)
796 add_reloc(&relocs64, offset);
797 else
798 add_reloc(&relocs32, offset);
799 break;
800
801 default:
802 die("Unsupported relocation type: %s (%d)\n",
803 rel_type(r_type), r_type);
804 break;
647 } 805 }
806
807 return 0;
648} 808}
649 809
650static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 810#else
811
812static int do_reloc32(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
813 const char *symname)
651{ 814{
652 if (ELF32_R_TYPE(rel->r_info) == R_386_16) 815 unsigned r_type = ELF32_R_TYPE(rel->r_info);
653 reloc16_count++; 816 int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
654 else 817
655 reloc_count++; 818 switch (r_type) {
819 case R_386_NONE:
820 case R_386_PC32:
821 case R_386_PC16:
822 case R_386_PC8:
823 /*
824 * NONE can be ignored and PC relative relocations don't
825 * need to be adjusted.
826 */
827 break;
828
829 case R_386_32:
830 if (shn_abs) {
831 /*
832 * Whitelisted absolute symbols do not require
833 * relocation.
834 */
835 if (is_reloc(S_ABS, symname))
836 break;
837
838 die("Invalid absolute %s relocation: %s\n",
839 rel_type(r_type), symname);
840 break;
841 }
842
843 add_reloc(&relocs32, rel->r_offset);
844 break;
845
846 default:
847 die("Unsupported relocation type: %s (%d)\n",
848 rel_type(r_type), r_type);
849 break;
850 }
851
852 return 0;
656} 853}
657 854
658static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) 855static int do_reloc_real(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
856 const char *symname)
659{ 857{
660 /* Remember the address that needs to be adjusted. */ 858 unsigned r_type = ELF32_R_TYPE(rel->r_info);
661 if (ELF32_R_TYPE(rel->r_info) == R_386_16) 859 int shn_abs = (sym->st_shndx == SHN_ABS) && !is_reloc(S_REL, symname);
662 relocs16[reloc16_idx++] = rel->r_offset; 860
663 else 861 switch (r_type) {
664 relocs[reloc_idx++] = rel->r_offset; 862 case R_386_NONE:
863 case R_386_PC32:
864 case R_386_PC16:
865 case R_386_PC8:
866 /*
867 * NONE can be ignored and PC relative relocations don't
868 * need to be adjusted.
869 */
870 break;
871
872 case R_386_16:
873 if (shn_abs) {
874 /*
875 * Whitelisted absolute symbols do not require
876 * relocation.
877 */
878 if (is_reloc(S_ABS, symname))
879 break;
880
881 if (is_reloc(S_SEG, symname)) {
882 add_reloc(&relocs16, rel->r_offset);
883 break;
884 }
885 } else {
886 if (!is_reloc(S_LIN, symname))
887 break;
888 }
889 die("Invalid %s %s relocation: %s\n",
890 shn_abs ? "absolute" : "relative",
891 rel_type(r_type), symname);
892 break;
893
894 case R_386_32:
895 if (shn_abs) {
896 /*
897 * Whitelisted absolute symbols do not require
898 * relocation.
899 */
900 if (is_reloc(S_ABS, symname))
901 break;
902
903 if (is_reloc(S_REL, symname)) {
904 add_reloc(&relocs32, rel->r_offset);
905 break;
906 }
907 } else {
908 if (is_reloc(S_LIN, symname))
909 add_reloc(&relocs32, rel->r_offset);
910 break;
911 }
912 die("Invalid %s %s relocation: %s\n",
913 shn_abs ? "absolute" : "relative",
914 rel_type(r_type), symname);
915 break;
916
917 default:
918 die("Unsupported relocation type: %s (%d)\n",
919 rel_type(r_type), r_type);
920 break;
921 }
922
923 return 0;
665} 924}
666 925
926#endif
927
667static int cmp_relocs(const void *va, const void *vb) 928static int cmp_relocs(const void *va, const void *vb)
668{ 929{
669 const unsigned long *a, *b; 930 const uint32_t *a, *b;
670 a = va; b = vb; 931 a = va; b = vb;
671 return (*a == *b)? 0 : (*a > *b)? 1 : -1; 932 return (*a == *b)? 0 : (*a > *b)? 1 : -1;
672} 933}
673 934
674static int write32(unsigned int v, FILE *f) 935static void sort_relocs(struct relocs *r)
936{
937 qsort(r->offset, r->count, sizeof(r->offset[0]), cmp_relocs);
938}
939
940static int write32(uint32_t v, FILE *f)
675{ 941{
676 unsigned char buf[4]; 942 unsigned char buf[4];
677 943
@@ -679,33 +945,40 @@ static int write32(unsigned int v, FILE *f)
679 return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; 945 return fwrite(buf, 1, 4, f) == 4 ? 0 : -1;
680} 946}
681 947
948static int write32_as_text(uint32_t v, FILE *f)
949{
950 return fprintf(f, "\t.long 0x%08"PRIx32"\n", v) > 0 ? 0 : -1;
951}
952
682static void emit_relocs(int as_text, int use_real_mode) 953static void emit_relocs(int as_text, int use_real_mode)
683{ 954{
684 int i; 955 int i;
685 /* Count how many relocations I have and allocate space for them. */ 956 int (*write_reloc)(uint32_t, FILE *) = write32;
686 reloc_count = 0; 957 int (*do_reloc)(struct section *sec, Elf_Rel *rel, Elf_Sym *sym,
687 walk_relocs(count_reloc, use_real_mode); 958 const char *symname);
688 relocs = malloc(reloc_count * sizeof(relocs[0])); 959
689 if (!relocs) { 960#if ELF_BITS == 64
690 die("malloc of %d entries for relocs failed\n", 961 if (!use_real_mode)
691 reloc_count); 962 do_reloc = do_reloc64;
692 } 963 else
964 die("--realmode not valid for a 64-bit ELF file");
965#else
966 if (!use_real_mode)
967 do_reloc = do_reloc32;
968 else
969 do_reloc = do_reloc_real;
970#endif
693 971
694 relocs16 = malloc(reloc16_count * sizeof(relocs[0]));
695 if (!relocs16) {
696 die("malloc of %d entries for relocs16 failed\n",
697 reloc16_count);
698 }
699 /* Collect up the relocations */ 972 /* Collect up the relocations */
700 reloc_idx = 0; 973 walk_relocs(do_reloc);
701 walk_relocs(collect_reloc, use_real_mode);
702 974
703 if (reloc16_count && !use_real_mode) 975 if (relocs16.count && !use_real_mode)
704 die("Segment relocations found but --realmode not specified\n"); 976 die("Segment relocations found but --realmode not specified\n");
705 977
706 /* Order the relocations for more efficient processing */ 978 /* Order the relocations for more efficient processing */
707 qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); 979 sort_relocs(&relocs16);
708 qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs); 980 sort_relocs(&relocs32);
981 sort_relocs(&relocs64);
709 982
710 /* Print the relocations */ 983 /* Print the relocations */
711 if (as_text) { 984 if (as_text) {
@@ -714,114 +987,60 @@ static void emit_relocs(int as_text, int use_real_mode)
714 */ 987 */
715 printf(".section \".data.reloc\",\"a\"\n"); 988 printf(".section \".data.reloc\",\"a\"\n");
716 printf(".balign 4\n"); 989 printf(".balign 4\n");
717 if (use_real_mode) { 990 write_reloc = write32_as_text;
718 printf("\t.long %lu\n", reloc16_count);
719 for (i = 0; i < reloc16_count; i++)
720 printf("\t.long 0x%08lx\n", relocs16[i]);
721 printf("\t.long %lu\n", reloc_count);
722 for (i = 0; i < reloc_count; i++) {
723 printf("\t.long 0x%08lx\n", relocs[i]);
724 }
725 } else {
726 /* Print a stop */
727 printf("\t.long 0x%08lx\n", (unsigned long)0);
728 for (i = 0; i < reloc_count; i++) {
729 printf("\t.long 0x%08lx\n", relocs[i]);
730 }
731 }
732
733 printf("\n");
734 } 991 }
735 else {
736 if (use_real_mode) {
737 write32(reloc16_count, stdout);
738 for (i = 0; i < reloc16_count; i++)
739 write32(relocs16[i], stdout);
740 write32(reloc_count, stdout);
741 992
742 /* Now print each relocation */ 993 if (use_real_mode) {
743 for (i = 0; i < reloc_count; i++) 994 write_reloc(relocs16.count, stdout);
744 write32(relocs[i], stdout); 995 for (i = 0; i < relocs16.count; i++)
745 } else { 996 write_reloc(relocs16.offset[i], stdout);
997
998 write_reloc(relocs32.count, stdout);
999 for (i = 0; i < relocs32.count; i++)
1000 write_reloc(relocs32.offset[i], stdout);
1001 } else {
1002 if (ELF_BITS == 64) {
746 /* Print a stop */ 1003 /* Print a stop */
747 write32(0, stdout); 1004 write_reloc(0, stdout);
748 1005
749 /* Now print each relocation */ 1006 /* Now print each relocation */
750 for (i = 0; i < reloc_count; i++) { 1007 for (i = 0; i < relocs64.count; i++)
751 write32(relocs[i], stdout); 1008 write_reloc(relocs64.offset[i], stdout);
752 }
753 } 1009 }
1010
1011 /* Print a stop */
1012 write_reloc(0, stdout);
1013
1014 /* Now print each relocation */
1015 for (i = 0; i < relocs32.count; i++)
1016 write_reloc(relocs32.offset[i], stdout);
754 } 1017 }
755} 1018}
756 1019
757static void usage(void) 1020#if ELF_BITS == 64
758{ 1021# define process process_64
759 die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n"); 1022#else
760} 1023# define process process_32
1024#endif
761 1025
762int main(int argc, char **argv) 1026void process(FILE *fp, int use_real_mode, int as_text,
1027 int show_absolute_syms, int show_absolute_relocs)
763{ 1028{
764 int show_absolute_syms, show_absolute_relocs;
765 int as_text, use_real_mode;
766 const char *fname;
767 FILE *fp;
768 int i;
769
770 show_absolute_syms = 0;
771 show_absolute_relocs = 0;
772 as_text = 0;
773 use_real_mode = 0;
774 fname = NULL;
775 for (i = 1; i < argc; i++) {
776 char *arg = argv[i];
777 if (*arg == '-') {
778 if (strcmp(arg, "--abs-syms") == 0) {
779 show_absolute_syms = 1;
780 continue;
781 }
782 if (strcmp(arg, "--abs-relocs") == 0) {
783 show_absolute_relocs = 1;
784 continue;
785 }
786 if (strcmp(arg, "--text") == 0) {
787 as_text = 1;
788 continue;
789 }
790 if (strcmp(arg, "--realmode") == 0) {
791 use_real_mode = 1;
792 continue;
793 }
794 }
795 else if (!fname) {
796 fname = arg;
797 continue;
798 }
799 usage();
800 }
801 if (!fname) {
802 usage();
803 }
804 regex_init(use_real_mode); 1029 regex_init(use_real_mode);
805 fp = fopen(fname, "r");
806 if (!fp) {
807 die("Cannot open %s: %s\n",
808 fname, strerror(errno));
809 }
810 read_ehdr(fp); 1030 read_ehdr(fp);
811 read_shdrs(fp); 1031 read_shdrs(fp);
812 read_strtabs(fp); 1032 read_strtabs(fp);
813 read_symtabs(fp); 1033 read_symtabs(fp);
814 read_relocs(fp); 1034 read_relocs(fp);
1035 if (ELF_BITS == 64)
1036 percpu_init();
815 if (show_absolute_syms) { 1037 if (show_absolute_syms) {
816 print_absolute_symbols(); 1038 print_absolute_symbols();
817 goto out; 1039 return;
818 } 1040 }
819 if (show_absolute_relocs) { 1041 if (show_absolute_relocs) {
820 print_absolute_relocs(); 1042 print_absolute_relocs();
821 goto out; 1043 return;
822 } 1044 }
823 emit_relocs(as_text, use_real_mode); 1045 emit_relocs(as_text, use_real_mode);
824out:
825 fclose(fp);
826 return 0;
827} 1046}
diff --git a/arch/x86/tools/relocs.h b/arch/x86/tools/relocs.h
new file mode 100644
index 000000000000..07cdb1eca4fa
--- /dev/null
+++ b/arch/x86/tools/relocs.h
@@ -0,0 +1,36 @@
1#ifndef RELOCS_H
2#define RELOCS_H
3
4#include <stdio.h>
5#include <stdarg.h>
6#include <stdlib.h>
7#include <stdint.h>
8#include <inttypes.h>
9#include <string.h>
10#include <errno.h>
11#include <unistd.h>
12#include <elf.h>
13#include <byteswap.h>
14#define USE_BSD
15#include <endian.h>
16#include <regex.h>
17#include <tools/le_byteshift.h>
18
19void die(char *fmt, ...);
20
21#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
22
23enum symtype {
24 S_ABS,
25 S_REL,
26 S_SEG,
27 S_LIN,
28 S_NSYMTYPES
29};
30
31void process_32(FILE *fp, int use_real_mode, int as_text,
32 int show_absolute_syms, int show_absolute_relocs);
33void process_64(FILE *fp, int use_real_mode, int as_text,
34 int show_absolute_syms, int show_absolute_relocs);
35
36#endif /* RELOCS_H */
diff --git a/arch/x86/tools/relocs_32.c b/arch/x86/tools/relocs_32.c
new file mode 100644
index 000000000000..b2ade2bb4162
--- /dev/null
+++ b/arch/x86/tools/relocs_32.c
@@ -0,0 +1,17 @@
1#include "relocs.h"
2
3#define ELF_BITS 32
4
5#define ELF_MACHINE EM_386
6#define ELF_MACHINE_NAME "i386"
7#define SHT_REL_TYPE SHT_REL
8#define Elf_Rel ElfW(Rel)
9
10#define ELF_CLASS ELFCLASS32
11#define ELF_R_SYM(val) ELF32_R_SYM(val)
12#define ELF_R_TYPE(val) ELF32_R_TYPE(val)
13#define ELF_ST_TYPE(o) ELF32_ST_TYPE(o)
14#define ELF_ST_BIND(o) ELF32_ST_BIND(o)
15#define ELF_ST_VISIBILITY(o) ELF32_ST_VISIBILITY(o)
16
17#include "relocs.c"
diff --git a/arch/x86/tools/relocs_64.c b/arch/x86/tools/relocs_64.c
new file mode 100644
index 000000000000..56b61b743c4c
--- /dev/null
+++ b/arch/x86/tools/relocs_64.c
@@ -0,0 +1,17 @@
1#include "relocs.h"
2
3#define ELF_BITS 64
4
5#define ELF_MACHINE EM_X86_64
6#define ELF_MACHINE_NAME "x86_64"
7#define SHT_REL_TYPE SHT_RELA
8#define Elf_Rel Elf64_Rela
9
10#define ELF_CLASS ELFCLASS64
11#define ELF_R_SYM(val) ELF64_R_SYM(val)
12#define ELF_R_TYPE(val) ELF64_R_TYPE(val)
13#define ELF_ST_TYPE(o) ELF64_ST_TYPE(o)
14#define ELF_ST_BIND(o) ELF64_ST_BIND(o)
15#define ELF_ST_VISIBILITY(o) ELF64_ST_VISIBILITY(o)
16
17#include "relocs.c"
diff --git a/arch/x86/tools/relocs_common.c b/arch/x86/tools/relocs_common.c
new file mode 100644
index 000000000000..44d396823a53
--- /dev/null
+++ b/arch/x86/tools/relocs_common.c
@@ -0,0 +1,76 @@
1#include "relocs.h"
2
3void die(char *fmt, ...)
4{
5 va_list ap;
6 va_start(ap, fmt);
7 vfprintf(stderr, fmt, ap);
8 va_end(ap);
9 exit(1);
10}
11
12static void usage(void)
13{
14 die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
15}
16
17int main(int argc, char **argv)
18{
19 int show_absolute_syms, show_absolute_relocs;
20 int as_text, use_real_mode;
21 const char *fname;
22 FILE *fp;
23 int i;
24 unsigned char e_ident[EI_NIDENT];
25
26 show_absolute_syms = 0;
27 show_absolute_relocs = 0;
28 as_text = 0;
29 use_real_mode = 0;
30 fname = NULL;
31 for (i = 1; i < argc; i++) {
32 char *arg = argv[i];
33 if (*arg == '-') {
34 if (strcmp(arg, "--abs-syms") == 0) {
35 show_absolute_syms = 1;
36 continue;
37 }
38 if (strcmp(arg, "--abs-relocs") == 0) {
39 show_absolute_relocs = 1;
40 continue;
41 }
42 if (strcmp(arg, "--text") == 0) {
43 as_text = 1;
44 continue;
45 }
46 if (strcmp(arg, "--realmode") == 0) {
47 use_real_mode = 1;
48 continue;
49 }
50 }
51 else if (!fname) {
52 fname = arg;
53 continue;
54 }
55 usage();
56 }
57 if (!fname) {
58 usage();
59 }
60 fp = fopen(fname, "r");
61 if (!fp) {
62 die("Cannot open %s: %s\n", fname, strerror(errno));
63 }
64 if (fread(&e_ident, 1, EI_NIDENT, fp) != EI_NIDENT) {
65 die("Cannot read %s: %s", fname, strerror(errno));
66 }
67 rewind(fp);
68 if (e_ident[EI_CLASS] == ELFCLASS64)
69 process_64(fp, use_real_mode, as_text,
70 show_absolute_syms, show_absolute_relocs);
71 else
72 process_32(fp, use_real_mode, as_text,
73 show_absolute_syms, show_absolute_relocs);
74 fclose(fp);
75 return 0;
76}
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index e006c18d288a..fdc3ba28ca38 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -2043,9 +2043,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
2043 2043
2044 switch (idx) { 2044 switch (idx) {
2045 case FIX_BTMAP_END ... FIX_BTMAP_BEGIN: 2045 case FIX_BTMAP_END ... FIX_BTMAP_BEGIN:
2046#ifdef CONFIG_X86_F00F_BUG 2046 case FIX_RO_IDT:
2047 case FIX_F00F_IDT:
2048#endif
2049#ifdef CONFIG_X86_32 2047#ifdef CONFIG_X86_32
2050 case FIX_WP_TEST: 2048 case FIX_WP_TEST:
2051 case FIX_VDSO: 2049 case FIX_VDSO: