diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-12-14 16:55:20 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-12-14 16:55:20 -0500 |
commit | 873b5271f878a11729fb4602c6ce967d0ff81119 (patch) | |
tree | d8f50af1ba3b6f331f618d291417f48c44d578b6 | |
parent | 494c2ebfb287eb10b229415063099e3700639028 (diff) |
x86: Regex support and known-movable symbols for relocs, fix _end
This adds a new category of symbols to the relocs program: symbols
which are known to be relative, even though the linker emits them as
absolute; this is the case for symbols that live in the linker script,
which currently applies to _end.
Unfortunately the previous workaround of putting _end in its own empty
section was defeated by newer binutils, which remove empty sections
completely.
This patch also changes the symbol matching to use regular expressions
instead of hardcoded C for specific patterns.
This is a decidedly non-minimal patch: a modified version of the
relocs program is used as part of the Syslinux build, and this is
basically a backport to Linux of some of those changes; they have
thus been well tested.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
LKML-Reference: <4AF86211.3070103@zytor.com>
Acked-by: Michal Marek <mmarek@suse.cz>
Tested-by: Sedat Dilek <sedat.dilek@gmail.com>
-rw-r--r-- | arch/x86/boot/compressed/relocs.c | 87 | ||||
-rw-r--r-- | arch/x86/kernel/vmlinux.lds.S | 4 |
2 files changed, 60 insertions, 31 deletions
diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c index bbeb0c3fbd90..89bbf4e4d05d 100644 --- a/arch/x86/boot/compressed/relocs.c +++ b/arch/x86/boot/compressed/relocs.c | |||
@@ -9,6 +9,9 @@ | |||
9 | #include <byteswap.h> | 9 | #include <byteswap.h> |
10 | #define USE_BSD | 10 | #define USE_BSD |
11 | #include <endian.h> | 11 | #include <endian.h> |
12 | #include <regex.h> | ||
13 | |||
14 | static void die(char *fmt, ...); | ||
12 | 15 | ||
13 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | 16 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
14 | static Elf32_Ehdr ehdr; | 17 | static Elf32_Ehdr ehdr; |
@@ -30,25 +33,47 @@ static struct section *secs; | |||
30 | * the address for which it has been compiled. Don't warn user about | 33 | * the address for which it has been compiled. Don't warn user about |
31 | * absolute relocations present w.r.t these symbols. | 34 | * absolute relocations present w.r.t these symbols. |
32 | */ | 35 | */ |
33 | static const char* safe_abs_relocs[] = { | 36 | static const char abs_sym_regex[] = |
34 | "xen_irq_disable_direct_reloc", | 37 | "^(xen_irq_disable_direct_reloc$|" |
35 | "xen_save_fl_direct_reloc", | 38 | "xen_save_fl_direct_reloc$|" |
36 | }; | 39 | "VDSO|" |
40 | "__crc_)"; | ||
41 | static regex_t abs_sym_regex_c; | ||
42 | static int is_abs_reloc(const char *sym_name) | ||
43 | { | ||
44 | return !regexec(&abs_sym_regex_c, sym_name, 0, NULL, 0); | ||
45 | } | ||
37 | 46 | ||
38 | static int is_safe_abs_reloc(const char* sym_name) | 47 | /* |
48 | * These symbols are known to be relative, even if the linker marks them | ||
49 | * as absolute (typically defined outside any section in the linker script.) | ||
50 | */ | ||
51 | static const char rel_sym_regex[] = | ||
52 | "^_end$"; | ||
53 | static regex_t rel_sym_regex_c; | ||
54 | static int is_rel_reloc(const char *sym_name) | ||
39 | { | 55 | { |
40 | int i; | 56 | return !regexec(&rel_sym_regex_c, sym_name, 0, NULL, 0); |
57 | } | ||
41 | 58 | ||
42 | for (i = 0; i < ARRAY_SIZE(safe_abs_relocs); i++) { | 59 | static void regex_init(void) |
43 | if (!strcmp(sym_name, safe_abs_relocs[i])) | 60 | { |
44 | /* Match found */ | 61 | char errbuf[128]; |
45 | return 1; | 62 | int err; |
46 | } | 63 | |
47 | if (strncmp(sym_name, "VDSO", 4) == 0) | 64 | err = regcomp(&abs_sym_regex_c, abs_sym_regex, |
48 | return 1; | 65 | REG_EXTENDED|REG_NOSUB); |
49 | if (strncmp(sym_name, "__crc_", 6) == 0) | 66 | if (err) { |
50 | return 1; | 67 | regerror(err, &abs_sym_regex_c, errbuf, sizeof errbuf); |
51 | return 0; | 68 | die("%s", errbuf); |
69 | } | ||
70 | |||
71 | err = regcomp(&rel_sym_regex_c, rel_sym_regex, | ||
72 | REG_EXTENDED|REG_NOSUB); | ||
73 | if (err) { | ||
74 | regerror(err, &rel_sym_regex_c, errbuf, sizeof errbuf); | ||
75 | die("%s", errbuf); | ||
76 | } | ||
52 | } | 77 | } |
53 | 78 | ||
54 | static void die(char *fmt, ...) | 79 | static void die(char *fmt, ...) |
@@ -131,7 +156,7 @@ static const char *rel_type(unsigned type) | |||
131 | #undef REL_TYPE | 156 | #undef REL_TYPE |
132 | }; | 157 | }; |
133 | const char *name = "unknown type rel type name"; | 158 | const char *name = "unknown type rel type name"; |
134 | if (type < ARRAY_SIZE(type_name)) { | 159 | if (type < ARRAY_SIZE(type_name) && type_name[type]) { |
135 | name = type_name[type]; | 160 | name = type_name[type]; |
136 | } | 161 | } |
137 | return name; | 162 | return name; |
@@ -448,7 +473,7 @@ static void print_absolute_relocs(void) | |||
448 | * Before warning check if this absolute symbol | 473 | * Before warning check if this absolute symbol |
449 | * relocation is harmless. | 474 | * relocation is harmless. |
450 | */ | 475 | */ |
451 | if (is_safe_abs_reloc(name)) | 476 | if (is_abs_reloc(name) || is_rel_reloc(name)) |
452 | continue; | 477 | continue; |
453 | 478 | ||
454 | if (!printed) { | 479 | if (!printed) { |
@@ -501,21 +526,26 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) | |||
501 | sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; | 526 | sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; |
502 | r_type = ELF32_R_TYPE(rel->r_info); | 527 | r_type = ELF32_R_TYPE(rel->r_info); |
503 | /* Don't visit relocations to absolute symbols */ | 528 | /* Don't visit relocations to absolute symbols */ |
504 | if (sym->st_shndx == SHN_ABS) { | 529 | if (sym->st_shndx == SHN_ABS && |
530 | !is_rel_reloc(sym_name(sym_strtab, sym))) { | ||
505 | continue; | 531 | continue; |
506 | } | 532 | } |
507 | if (r_type == R_386_NONE || r_type == R_386_PC32) { | 533 | switch (r_type) { |
534 | case R_386_NONE: | ||
535 | case R_386_PC32: | ||
508 | /* | 536 | /* |
509 | * NONE can be ignored and and PC relative | 537 | * NONE can be ignored and and PC relative |
510 | * relocations don't need to be adjusted. | 538 | * relocations don't need to be adjusted. |
511 | */ | 539 | */ |
512 | } | 540 | break; |
513 | else if (r_type == R_386_32) { | 541 | case R_386_32: |
514 | /* Visit relocations that need to be adjusted */ | 542 | /* Visit relocations that need to be adjusted */ |
515 | visit(rel, sym); | 543 | visit(rel, sym); |
516 | } | 544 | break; |
517 | else { | 545 | default: |
518 | die("Unsupported relocation type: %d\n", r_type); | 546 | die("Unsupported relocation type: %s (%d)\n", |
547 | rel_type(r_type), r_type); | ||
548 | break; | ||
519 | } | 549 | } |
520 | } | 550 | } |
521 | } | 551 | } |
@@ -571,16 +601,15 @@ static void emit_relocs(int as_text) | |||
571 | } | 601 | } |
572 | else { | 602 | else { |
573 | unsigned char buf[4]; | 603 | unsigned char buf[4]; |
574 | buf[0] = buf[1] = buf[2] = buf[3] = 0; | ||
575 | /* Print a stop */ | 604 | /* Print a stop */ |
576 | printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); | 605 | fwrite("\0\0\0\0", 4, 1, stdout); |
577 | /* Now print each relocation */ | 606 | /* Now print each relocation */ |
578 | for (i = 0; i < reloc_count; i++) { | 607 | for (i = 0; i < reloc_count; i++) { |
579 | buf[0] = (relocs[i] >> 0) & 0xff; | 608 | buf[0] = (relocs[i] >> 0) & 0xff; |
580 | buf[1] = (relocs[i] >> 8) & 0xff; | 609 | buf[1] = (relocs[i] >> 8) & 0xff; |
581 | buf[2] = (relocs[i] >> 16) & 0xff; | 610 | buf[2] = (relocs[i] >> 16) & 0xff; |
582 | buf[3] = (relocs[i] >> 24) & 0xff; | 611 | buf[3] = (relocs[i] >> 24) & 0xff; |
583 | printf("%c%c%c%c", buf[0], buf[1], buf[2], buf[3]); | 612 | fwrite(buf, 4, 1, stdout); |
584 | } | 613 | } |
585 | } | 614 | } |
586 | } | 615 | } |
@@ -598,6 +627,8 @@ int main(int argc, char **argv) | |||
598 | FILE *fp; | 627 | FILE *fp; |
599 | int i; | 628 | int i; |
600 | 629 | ||
630 | regex_init(); | ||
631 | |||
601 | show_absolute_syms = 0; | 632 | show_absolute_syms = 0; |
602 | show_absolute_relocs = 0; | 633 | show_absolute_relocs = 0; |
603 | as_text = 0; | 634 | as_text = 0; |
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index f3f2104408d9..f92a0da608cb 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S | |||
@@ -319,9 +319,7 @@ SECTIONS | |||
319 | __brk_limit = .; | 319 | __brk_limit = .; |
320 | } | 320 | } |
321 | 321 | ||
322 | .end : AT(ADDR(.end) - LOAD_OFFSET) { | 322 | _end = .; |
323 | _end = .; | ||
324 | } | ||
325 | 323 | ||
326 | STABS_DEBUG | 324 | STABS_DEBUG |
327 | DWARF_DEBUG | 325 | DWARF_DEBUG |