Commit d59a16836d917548cf41eda3369936684d527f5f
Committed by
H. Peter Anvin
1 parent
706276543b
Exists in
master
and in
20 other branches
scripts/sortextable: Handle relative entries, and other cleanups
x86 is now using relative rather than absolute addresses in its exception table, so we add a sorter for these. If there are relocations on the __ex_table section, they are redundant and probably incorrect after the sort, so they are zeroed out leaving them valid and consistent. Also use the unaligned safe accessors from tools/{be,le}_byteshift.h Signed-off-by: David Daney <david.daney@cavium.com> Link: http://lkml.kernel.org/r/1335291795-26693-2-git-send-email-ddaney.cavm@gmail.com Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Showing 3 changed files with 164 additions and 88 deletions Side-by-side Diff
scripts/Makefile
... | ... | @@ -15,6 +15,8 @@ |
15 | 15 | hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount |
16 | 16 | hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable |
17 | 17 | |
18 | +HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include | |
19 | + | |
18 | 20 | always := $(hostprogs-y) $(hostprogs-m) |
19 | 21 | |
20 | 22 | # The following hostprogs-y programs are only build on demand |
scripts/sortextable.c
1 | 1 | /* |
2 | 2 | * sortextable.c: Sort the kernel's exception table |
3 | 3 | * |
4 | - * Copyright 2011 Cavium, Inc. | |
4 | + * Copyright 2011 - 2012 Cavium, Inc. | |
5 | 5 | * |
6 | 6 | * Based on code taken from recortmcount.c which is: |
7 | 7 | * |
... | ... | @@ -28,6 +28,9 @@ |
28 | 28 | #include <string.h> |
29 | 29 | #include <unistd.h> |
30 | 30 | |
31 | +#include <tools/be_byteshift.h> | |
32 | +#include <tools/le_byteshift.h> | |
33 | + | |
31 | 34 | static int fd_map; /* File descriptor for file being modified. */ |
32 | 35 | static int mmap_failed; /* Boolean flag. */ |
33 | 36 | static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ |
34 | 37 | |
35 | 38 | |
36 | 39 | |
37 | 40 | |
38 | 41 | |
39 | 42 | |
40 | 43 | |
41 | 44 | |
42 | 45 | |
43 | 46 | |
44 | 47 | |
45 | 48 | |
46 | 49 | |
47 | 50 | |
48 | 51 | |
49 | 52 | |
50 | 53 | |
51 | 54 | |
52 | 55 | |
53 | 56 | |
54 | 57 | |
55 | 58 | |
56 | 59 | |
57 | 60 | |
58 | 61 | |
59 | 62 | |
60 | 63 | |
61 | 64 | |
... | ... | @@ -94,110 +97,158 @@ |
94 | 97 | return addr; |
95 | 98 | } |
96 | 99 | |
97 | -/* w8rev, w8nat, ...: Handle endianness. */ | |
98 | - | |
99 | -static uint64_t w8rev(uint64_t const x) | |
100 | +static uint64_t r8be(const uint64_t *x) | |
100 | 101 | { |
101 | - return ((0xff & (x >> (0 * 8))) << (7 * 8)) | |
102 | - | ((0xff & (x >> (1 * 8))) << (6 * 8)) | |
103 | - | ((0xff & (x >> (2 * 8))) << (5 * 8)) | |
104 | - | ((0xff & (x >> (3 * 8))) << (4 * 8)) | |
105 | - | ((0xff & (x >> (4 * 8))) << (3 * 8)) | |
106 | - | ((0xff & (x >> (5 * 8))) << (2 * 8)) | |
107 | - | ((0xff & (x >> (6 * 8))) << (1 * 8)) | |
108 | - | ((0xff & (x >> (7 * 8))) << (0 * 8)); | |
102 | + return get_unaligned_be64(x); | |
109 | 103 | } |
110 | - | |
111 | -static uint32_t w4rev(uint32_t const x) | |
104 | +static uint32_t rbe(const uint32_t *x) | |
112 | 105 | { |
113 | - return ((0xff & (x >> (0 * 8))) << (3 * 8)) | |
114 | - | ((0xff & (x >> (1 * 8))) << (2 * 8)) | |
115 | - | ((0xff & (x >> (2 * 8))) << (1 * 8)) | |
116 | - | ((0xff & (x >> (3 * 8))) << (0 * 8)); | |
106 | + return get_unaligned_be32(x); | |
117 | 107 | } |
118 | - | |
119 | -static uint32_t w2rev(uint16_t const x) | |
108 | +static uint16_t r2be(const uint16_t *x) | |
120 | 109 | { |
121 | - return ((0xff & (x >> (0 * 8))) << (1 * 8)) | |
122 | - | ((0xff & (x >> (1 * 8))) << (0 * 8)); | |
110 | + return get_unaligned_be16(x); | |
123 | 111 | } |
124 | - | |
125 | -static uint64_t w8nat(uint64_t const x) | |
112 | +static uint64_t r8le(const uint64_t *x) | |
126 | 113 | { |
127 | - return x; | |
114 | + return get_unaligned_le64(x); | |
128 | 115 | } |
129 | - | |
130 | -static uint32_t w4nat(uint32_t const x) | |
116 | +static uint32_t rle(const uint32_t *x) | |
131 | 117 | { |
132 | - return x; | |
118 | + return get_unaligned_le32(x); | |
133 | 119 | } |
120 | +static uint16_t r2le(const uint16_t *x) | |
121 | +{ | |
122 | + return get_unaligned_le16(x); | |
123 | +} | |
134 | 124 | |
135 | -static uint32_t w2nat(uint16_t const x) | |
125 | +static void w8be(uint64_t val, uint64_t *x) | |
136 | 126 | { |
137 | - return x; | |
127 | + put_unaligned_be64(val, x); | |
138 | 128 | } |
129 | +static void wbe(uint32_t val, uint32_t *x) | |
130 | +{ | |
131 | + put_unaligned_be32(val, x); | |
132 | +} | |
133 | +static void w2be(uint16_t val, uint16_t *x) | |
134 | +{ | |
135 | + put_unaligned_be16(val, x); | |
136 | +} | |
137 | +static void w8le(uint64_t val, uint64_t *x) | |
138 | +{ | |
139 | + put_unaligned_le64(val, x); | |
140 | +} | |
141 | +static void wle(uint32_t val, uint32_t *x) | |
142 | +{ | |
143 | + put_unaligned_le32(val, x); | |
144 | +} | |
145 | +static void w2le(uint16_t val, uint16_t *x) | |
146 | +{ | |
147 | + put_unaligned_le16(val, x); | |
148 | +} | |
139 | 149 | |
140 | -static uint64_t (*w8)(uint64_t); | |
141 | -static uint32_t (*w)(uint32_t); | |
142 | -static uint32_t (*w2)(uint16_t); | |
150 | +static uint64_t (*r8)(const uint64_t *); | |
151 | +static uint32_t (*r)(const uint32_t *); | |
152 | +static uint16_t (*r2)(const uint16_t *); | |
153 | +static void (*w8)(uint64_t, uint64_t *); | |
154 | +static void (*w)(uint32_t, uint32_t *); | |
155 | +static void (*w2)(uint16_t, uint16_t *); | |
143 | 156 | |
157 | +typedef void (*table_sort_t)(char *, int); | |
144 | 158 | |
145 | 159 | /* 32 bit and 64 bit are very similar */ |
146 | 160 | #include "sortextable.h" |
147 | 161 | #define SORTEXTABLE_64 |
148 | 162 | #include "sortextable.h" |
149 | 163 | |
164 | +static int compare_x86_table(const void *a, const void *b) | |
165 | +{ | |
166 | + int32_t av = (int32_t)r(a); | |
167 | + int32_t bv = (int32_t)r(b); | |
150 | 168 | |
169 | + if (av < bv) | |
170 | + return -1; | |
171 | + if (av > bv) | |
172 | + return 1; | |
173 | + return 0; | |
174 | +} | |
175 | + | |
176 | +static void sort_x86_table(char *extab_image, int image_size) | |
177 | +{ | |
178 | + int i; | |
179 | + | |
180 | + /* | |
181 | + * Do the same thing the runtime sort does, first normalize to | |
182 | + * being relative to the start of the section. | |
183 | + */ | |
184 | + i = 0; | |
185 | + while (i < image_size) { | |
186 | + uint32_t *loc = (uint32_t *)(extab_image + i); | |
187 | + w(r(loc) + i, loc); | |
188 | + i += 4; | |
189 | + } | |
190 | + | |
191 | + qsort(extab_image, image_size / 8, 8, compare_x86_table); | |
192 | + | |
193 | + /* Now denormalize. */ | |
194 | + i = 0; | |
195 | + while (i < image_size) { | |
196 | + uint32_t *loc = (uint32_t *)(extab_image + i); | |
197 | + w(r(loc) - i, loc); | |
198 | + i += 4; | |
199 | + } | |
200 | +} | |
201 | + | |
151 | 202 | static void |
152 | 203 | do_file(char const *const fname) |
153 | 204 | { |
154 | - Elf32_Ehdr *const ehdr = mmap_file(fname); | |
205 | + table_sort_t custom_sort; | |
206 | + Elf32_Ehdr *ehdr = mmap_file(fname); | |
155 | 207 | |
156 | 208 | ehdr_curr = ehdr; |
157 | - w = w4nat; | |
158 | - w2 = w2nat; | |
159 | - w8 = w8nat; | |
160 | 209 | switch (ehdr->e_ident[EI_DATA]) { |
161 | - static unsigned int const endian = 1; | |
162 | 210 | default: |
163 | 211 | fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", |
164 | 212 | ehdr->e_ident[EI_DATA], fname); |
165 | 213 | fail_file(); |
166 | 214 | break; |
167 | 215 | case ELFDATA2LSB: |
168 | - if (*(unsigned char const *)&endian != 1) { | |
169 | - /* main() is big endian, file.o is little endian. */ | |
170 | - w = w4rev; | |
171 | - w2 = w2rev; | |
172 | - w8 = w8rev; | |
173 | - } | |
216 | + r = rle; | |
217 | + r2 = r2le; | |
218 | + r8 = r8le; | |
219 | + w = wle; | |
220 | + w2 = w2le; | |
221 | + w8 = w8le; | |
174 | 222 | break; |
175 | 223 | case ELFDATA2MSB: |
176 | - if (*(unsigned char const *)&endian != 0) { | |
177 | - /* main() is little endian, file.o is big endian. */ | |
178 | - w = w4rev; | |
179 | - w2 = w2rev; | |
180 | - w8 = w8rev; | |
181 | - } | |
224 | + r = rbe; | |
225 | + r2 = r2be; | |
226 | + r8 = r8be; | |
227 | + w = wbe; | |
228 | + w2 = w2be; | |
229 | + w8 = w8be; | |
182 | 230 | break; |
183 | 231 | } /* end switch */ |
184 | 232 | if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 |
185 | - || w2(ehdr->e_type) != ET_EXEC | |
233 | + || r2(&ehdr->e_type) != ET_EXEC | |
186 | 234 | || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { |
187 | 235 | fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); |
188 | 236 | fail_file(); |
189 | 237 | } |
190 | 238 | |
191 | - switch (w2(ehdr->e_machine)) { | |
239 | + custom_sort = NULL; | |
240 | + switch (r2(&ehdr->e_machine)) { | |
192 | 241 | default: |
193 | 242 | fprintf(stderr, "unrecognized e_machine %d %s\n", |
194 | - w2(ehdr->e_machine), fname); | |
243 | + r2(&ehdr->e_machine), fname); | |
195 | 244 | fail_file(); |
196 | 245 | break; |
197 | 246 | case EM_386: |
198 | - case EM_MIPS: | |
199 | 247 | case EM_X86_64: |
248 | + custom_sort = sort_x86_table; | |
200 | 249 | break; |
250 | + case EM_MIPS: | |
251 | + break; | |
201 | 252 | } /* end switch */ |
202 | 253 | |
203 | 254 | switch (ehdr->e_ident[EI_CLASS]) { |
204 | 255 | |
205 | 256 | |
206 | 257 | |
... | ... | @@ -207,23 +258,23 @@ |
207 | 258 | fail_file(); |
208 | 259 | break; |
209 | 260 | case ELFCLASS32: |
210 | - if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) | |
211 | - || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { | |
261 | + if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) | |
262 | + || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { | |
212 | 263 | fprintf(stderr, |
213 | 264 | "unrecognized ET_EXEC file: %s\n", fname); |
214 | 265 | fail_file(); |
215 | 266 | } |
216 | - do32(ehdr, fname); | |
267 | + do32(ehdr, fname, custom_sort); | |
217 | 268 | break; |
218 | 269 | case ELFCLASS64: { |
219 | 270 | Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; |
220 | - if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) | |
221 | - || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { | |
271 | + if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) | |
272 | + || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { | |
222 | 273 | fprintf(stderr, |
223 | 274 | "unrecognized ET_EXEC file: %s\n", fname); |
224 | 275 | fail_file(); |
225 | 276 | } |
226 | - do64(ghdr, fname); | |
277 | + do64(ghdr, fname, custom_sort); | |
227 | 278 | break; |
228 | 279 | } |
229 | 280 | } /* end switch */ |
scripts/sortextable.h
1 | 1 | /* |
2 | 2 | * sortextable.h |
3 | 3 | * |
4 | - * Copyright 2011 Cavium, Inc. | |
4 | + * Copyright 2011 - 2012 Cavium, Inc. | |
5 | 5 | * |
6 | 6 | * Some of this code was taken out of recordmcount.h written by: |
7 | 7 | * |
... | ... | @@ -30,6 +30,7 @@ |
30 | 30 | #undef fn_ELF_R_SYM |
31 | 31 | #undef fn_ELF_R_INFO |
32 | 32 | #undef uint_t |
33 | +#undef _r | |
33 | 34 | #undef _w |
34 | 35 | |
35 | 36 | #ifdef SORTEXTABLE_64 |
... | ... | @@ -51,6 +52,7 @@ |
51 | 52 | # define fn_ELF_R_SYM fn_ELF64_R_SYM |
52 | 53 | # define fn_ELF_R_INFO fn_ELF64_R_INFO |
53 | 54 | # define uint_t uint64_t |
55 | +# define _r r8 | |
54 | 56 | # define _w w8 |
55 | 57 | #else |
56 | 58 | # define extable_ent_size 8 |
57 | 59 | |
58 | 60 | |
59 | 61 | |
60 | 62 | |
... | ... | @@ -71,23 +73,24 @@ |
71 | 73 | # define fn_ELF_R_SYM fn_ELF32_R_SYM |
72 | 74 | # define fn_ELF_R_INFO fn_ELF32_R_INFO |
73 | 75 | # define uint_t uint32_t |
76 | +# define _r r | |
74 | 77 | # define _w w |
75 | 78 | #endif |
76 | 79 | |
77 | 80 | static int compare_extable(const void *a, const void *b) |
78 | 81 | { |
79 | - const uint_t *aa = a; | |
80 | - const uint_t *bb = b; | |
82 | + Elf_Addr av = _r(a); | |
83 | + Elf_Addr bv = _r(b); | |
81 | 84 | |
82 | - if (_w(*aa) < _w(*bb)) | |
85 | + if (av < bv) | |
83 | 86 | return -1; |
84 | - if (_w(*aa) > _w(*bb)) | |
87 | + if (av > bv) | |
85 | 88 | return 1; |
86 | 89 | return 0; |
87 | 90 | } |
88 | 91 | |
89 | 92 | static void |
90 | -do_func(Elf_Ehdr *const ehdr, char const *const fname) | |
93 | +do_func(Elf_Ehdr *ehdr, char const *const fname, table_sort_t custom_sort) | |
91 | 94 | { |
92 | 95 | Elf_Shdr *shdr; |
93 | 96 | Elf_Shdr *shstrtab_sec; |
94 | 97 | |
95 | 98 | |
96 | 99 | |
... | ... | @@ -97,19 +100,31 @@ |
97 | 100 | Elf_Sym *sym; |
98 | 101 | Elf_Sym *sort_needed_sym; |
99 | 102 | Elf_Shdr *sort_needed_sec; |
103 | + Elf_Rel *relocs = NULL; | |
104 | + int relocs_size; | |
100 | 105 | uint32_t *sort_done_location; |
101 | 106 | const char *secstrtab; |
102 | 107 | const char *strtab; |
108 | + char *extab_image; | |
109 | + int extab_index = 0; | |
103 | 110 | int i; |
104 | 111 | int idx; |
105 | 112 | |
106 | - shdr = (Elf_Shdr *)((void *)ehdr + _w(ehdr->e_shoff)); | |
107 | - shstrtab_sec = shdr + w2(ehdr->e_shstrndx); | |
108 | - secstrtab = (const char *)ehdr + _w(shstrtab_sec->sh_offset); | |
109 | - for (i = 0; i < w2(ehdr->e_shnum); i++) { | |
110 | - idx = w(shdr[i].sh_name); | |
111 | - if (strcmp(secstrtab + idx, "__ex_table") == 0) | |
113 | + shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff)); | |
114 | + shstrtab_sec = shdr + r2(&ehdr->e_shstrndx); | |
115 | + secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset); | |
116 | + for (i = 0; i < r2(&ehdr->e_shnum); i++) { | |
117 | + idx = r(&shdr[i].sh_name); | |
118 | + if (strcmp(secstrtab + idx, "__ex_table") == 0) { | |
112 | 119 | extab_sec = shdr + i; |
120 | + extab_index = i; | |
121 | + } | |
122 | + if ((r(&shdr[i].sh_type) == SHT_REL || | |
123 | + r(&shdr[i].sh_type) == SHT_RELA) && | |
124 | + r(&shdr[i].sh_info) == extab_index) { | |
125 | + relocs = (void *)ehdr + _r(&shdr[i].sh_offset); | |
126 | + relocs_size = _r(&shdr[i].sh_size); | |
127 | + } | |
113 | 128 | if (strcmp(secstrtab + idx, ".symtab") == 0) |
114 | 129 | symtab_sec = shdr + i; |
115 | 130 | if (strcmp(secstrtab + idx, ".strtab") == 0) |
116 | 131 | |
117 | 132 | |
118 | 133 | |
119 | 134 | |
... | ... | @@ -127,21 +142,29 @@ |
127 | 142 | fprintf(stderr, "no __ex_table in file: %s\n", fname); |
128 | 143 | fail_file(); |
129 | 144 | } |
130 | - strtab = (const char *)ehdr + _w(strtab_sec->sh_offset); | |
145 | + strtab = (const char *)ehdr + _r(&strtab_sec->sh_offset); | |
131 | 146 | |
132 | - /* Sort the table in place */ | |
133 | - qsort((void *)ehdr + _w(extab_sec->sh_offset), | |
134 | - (_w(extab_sec->sh_size) / extable_ent_size), | |
135 | - extable_ent_size, compare_extable); | |
147 | + extab_image = (void *)ehdr + _r(&extab_sec->sh_offset); | |
136 | 148 | |
149 | + if (custom_sort) { | |
150 | + custom_sort(extab_image, _r(&extab_sec->sh_size)); | |
151 | + } else { | |
152 | + int num_entries = _r(&extab_sec->sh_size) / extable_ent_size; | |
153 | + qsort(extab_image, num_entries, | |
154 | + extable_ent_size, compare_extable); | |
155 | + } | |
156 | + /* If there were relocations, we no longer need them. */ | |
157 | + if (relocs) | |
158 | + memset(relocs, 0, relocs_size); | |
159 | + | |
137 | 160 | /* find main_extable_sort_needed */ |
138 | 161 | sort_needed_sym = NULL; |
139 | - for (i = 0; i < _w(symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { | |
140 | - sym = (void *)ehdr + _w(symtab_sec->sh_offset); | |
162 | + for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { | |
163 | + sym = (void *)ehdr + _r(&symtab_sec->sh_offset); | |
141 | 164 | sym += i; |
142 | 165 | if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) |
143 | 166 | continue; |
144 | - idx = w(sym->st_name); | |
167 | + idx = r(&sym->st_name); | |
145 | 168 | if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { |
146 | 169 | sort_needed_sym = sym; |
147 | 170 | break; |
148 | 171 | |
149 | 172 | |
150 | 173 | |
151 | 174 | |
... | ... | @@ -153,17 +176,17 @@ |
153 | 176 | fname); |
154 | 177 | fail_file(); |
155 | 178 | } |
156 | - sort_needed_sec = &shdr[w2(sort_needed_sym->st_shndx)]; | |
179 | + sort_needed_sec = &shdr[r2(&sort_needed_sym->st_shndx)]; | |
157 | 180 | sort_done_location = (void *)ehdr + |
158 | - _w(sort_needed_sec->sh_offset) + | |
159 | - _w(sort_needed_sym->st_value) - | |
160 | - _w(sort_needed_sec->sh_addr); | |
181 | + _r(&sort_needed_sec->sh_offset) + | |
182 | + _r(&sort_needed_sym->st_value) - | |
183 | + _r(&sort_needed_sec->sh_addr); | |
161 | 184 | |
185 | +#if 1 | |
162 | 186 | printf("sort done marker at %lx\n", |
163 | - (unsigned long) (_w(sort_needed_sec->sh_offset) + | |
164 | - _w(sort_needed_sym->st_value) - | |
165 | - _w(sort_needed_sec->sh_addr))); | |
187 | + (unsigned long)((char *)sort_done_location - (char *)ehdr)); | |
188 | +#endif | |
166 | 189 | /* We sorted it, clear the flag. */ |
167 | - *sort_done_location = 0; | |
190 | + w(0, sort_done_location); | |
168 | 191 | } |