diff options
author | David Daney <david.daney@cavium.com> | 2012-04-24 14:23:14 -0400 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2012-04-24 14:42:20 -0400 |
commit | d59a16836d917548cf41eda3369936684d527f5f (patch) | |
tree | a332ee65290db2a53fb3cfca6e97de2a622c3df6 /scripts/sortextable.c | |
parent | 706276543b699d80f546e45f8b12574e7b18d952 (diff) |
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>
Diffstat (limited to 'scripts/sortextable.c')
-rw-r--r-- | scripts/sortextable.c | 171 |
1 files changed, 111 insertions, 60 deletions
diff --git a/scripts/sortextable.c b/scripts/sortextable.c index f51f1d43da63..1ca9ceb95eb6 100644 --- a/scripts/sortextable.c +++ b/scripts/sortextable.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * sortextable.c: Sort the kernel's exception table | 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 | * Based on code taken from recortmcount.c which is: | 6 | * Based on code taken from recortmcount.c which is: |
7 | * | 7 | * |
@@ -28,6 +28,9 @@ | |||
28 | #include <string.h> | 28 | #include <string.h> |
29 | #include <unistd.h> | 29 | #include <unistd.h> |
30 | 30 | ||
31 | #include <tools/be_byteshift.h> | ||
32 | #include <tools/le_byteshift.h> | ||
33 | |||
31 | static int fd_map; /* File descriptor for file being modified. */ | 34 | static int fd_map; /* File descriptor for file being modified. */ |
32 | static int mmap_failed; /* Boolean flag. */ | 35 | static int mmap_failed; /* Boolean flag. */ |
33 | static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ | 36 | static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ |
@@ -94,109 +97,157 @@ static void *mmap_file(char const *fname) | |||
94 | return addr; | 97 | return addr; |
95 | } | 98 | } |
96 | 99 | ||
97 | /* w8rev, w8nat, ...: Handle endianness. */ | 100 | static uint64_t r8be(const uint64_t *x) |
98 | |||
99 | static uint64_t w8rev(uint64_t const x) | ||
100 | { | 101 | { |
101 | return ((0xff & (x >> (0 * 8))) << (7 * 8)) | 102 | return get_unaligned_be64(x); |
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)); | ||
109 | } | 103 | } |
110 | 104 | static uint32_t rbe(const uint32_t *x) | |
111 | static uint32_t w4rev(uint32_t const x) | ||
112 | { | 105 | { |
113 | return ((0xff & (x >> (0 * 8))) << (3 * 8)) | 106 | return get_unaligned_be32(x); |
114 | | ((0xff & (x >> (1 * 8))) << (2 * 8)) | ||
115 | | ((0xff & (x >> (2 * 8))) << (1 * 8)) | ||
116 | | ((0xff & (x >> (3 * 8))) << (0 * 8)); | ||
117 | } | 107 | } |
118 | 108 | static uint16_t r2be(const uint16_t *x) | |
119 | static uint32_t w2rev(uint16_t const x) | ||
120 | { | 109 | { |
121 | return ((0xff & (x >> (0 * 8))) << (1 * 8)) | 110 | return get_unaligned_be16(x); |
122 | | ((0xff & (x >> (1 * 8))) << (0 * 8)); | ||
123 | } | 111 | } |
124 | 112 | static uint64_t r8le(const uint64_t *x) | |
125 | static uint64_t w8nat(uint64_t const x) | ||
126 | { | 113 | { |
127 | return x; | 114 | return get_unaligned_le64(x); |
128 | } | 115 | } |
129 | 116 | static uint32_t rle(const uint32_t *x) | |
130 | static uint32_t w4nat(uint32_t const x) | 117 | { |
118 | return get_unaligned_le32(x); | ||
119 | } | ||
120 | static uint16_t r2le(const uint16_t *x) | ||
131 | { | 121 | { |
132 | return x; | 122 | return get_unaligned_le16(x); |
133 | } | 123 | } |
134 | 124 | ||
135 | static uint32_t w2nat(uint16_t const x) | 125 | static void w8be(uint64_t val, uint64_t *x) |
126 | { | ||
127 | put_unaligned_be64(val, x); | ||
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) | ||
136 | { | 146 | { |
137 | return x; | 147 | put_unaligned_le16(val, x); |
138 | } | 148 | } |
139 | 149 | ||
140 | static uint64_t (*w8)(uint64_t); | 150 | static uint64_t (*r8)(const uint64_t *); |
141 | static uint32_t (*w)(uint32_t); | 151 | static uint32_t (*r)(const uint32_t *); |
142 | static uint32_t (*w2)(uint16_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 | /* 32 bit and 64 bit are very similar */ | 159 | /* 32 bit and 64 bit are very similar */ |
146 | #include "sortextable.h" | 160 | #include "sortextable.h" |
147 | #define SORTEXTABLE_64 | 161 | #define SORTEXTABLE_64 |
148 | #include "sortextable.h" | 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); | ||
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 | } | ||
150 | 201 | ||
151 | static void | 202 | static void |
152 | do_file(char const *const fname) | 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 | ehdr_curr = ehdr; | 208 | ehdr_curr = ehdr; |
157 | w = w4nat; | ||
158 | w2 = w2nat; | ||
159 | w8 = w8nat; | ||
160 | switch (ehdr->e_ident[EI_DATA]) { | 209 | switch (ehdr->e_ident[EI_DATA]) { |
161 | static unsigned int const endian = 1; | ||
162 | default: | 210 | default: |
163 | fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", | 211 | fprintf(stderr, "unrecognized ELF data encoding %d: %s\n", |
164 | ehdr->e_ident[EI_DATA], fname); | 212 | ehdr->e_ident[EI_DATA], fname); |
165 | fail_file(); | 213 | fail_file(); |
166 | break; | 214 | break; |
167 | case ELFDATA2LSB: | 215 | case ELFDATA2LSB: |
168 | if (*(unsigned char const *)&endian != 1) { | 216 | r = rle; |
169 | /* main() is big endian, file.o is little endian. */ | 217 | r2 = r2le; |
170 | w = w4rev; | 218 | r8 = r8le; |
171 | w2 = w2rev; | 219 | w = wle; |
172 | w8 = w8rev; | 220 | w2 = w2le; |
173 | } | 221 | w8 = w8le; |
174 | break; | 222 | break; |
175 | case ELFDATA2MSB: | 223 | case ELFDATA2MSB: |
176 | if (*(unsigned char const *)&endian != 0) { | 224 | r = rbe; |
177 | /* main() is little endian, file.o is big endian. */ | 225 | r2 = r2be; |
178 | w = w4rev; | 226 | r8 = r8be; |
179 | w2 = w2rev; | 227 | w = wbe; |
180 | w8 = w8rev; | 228 | w2 = w2be; |
181 | } | 229 | w8 = w8be; |
182 | break; | 230 | break; |
183 | } /* end switch */ | 231 | } /* end switch */ |
184 | if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 | 232 | if (memcmp(ELFMAG, ehdr->e_ident, SELFMAG) != 0 |
185 | || w2(ehdr->e_type) != ET_EXEC | 233 | || r2(&ehdr->e_type) != ET_EXEC |
186 | || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { | 234 | || ehdr->e_ident[EI_VERSION] != EV_CURRENT) { |
187 | fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); | 235 | fprintf(stderr, "unrecognized ET_EXEC file %s\n", fname); |
188 | fail_file(); | 236 | fail_file(); |
189 | } | 237 | } |
190 | 238 | ||
191 | switch (w2(ehdr->e_machine)) { | 239 | custom_sort = NULL; |
240 | switch (r2(&ehdr->e_machine)) { | ||
192 | default: | 241 | default: |
193 | fprintf(stderr, "unrecognized e_machine %d %s\n", | 242 | fprintf(stderr, "unrecognized e_machine %d %s\n", |
194 | w2(ehdr->e_machine), fname); | 243 | r2(&ehdr->e_machine), fname); |
195 | fail_file(); | 244 | fail_file(); |
196 | break; | 245 | break; |
197 | case EM_386: | 246 | case EM_386: |
198 | case EM_MIPS: | ||
199 | case EM_X86_64: | 247 | case EM_X86_64: |
248 | custom_sort = sort_x86_table; | ||
249 | break; | ||
250 | case EM_MIPS: | ||
200 | break; | 251 | break; |
201 | } /* end switch */ | 252 | } /* end switch */ |
202 | 253 | ||
@@ -207,23 +258,23 @@ do_file(char const *const fname) | |||
207 | fail_file(); | 258 | fail_file(); |
208 | break; | 259 | break; |
209 | case ELFCLASS32: | 260 | case ELFCLASS32: |
210 | if (w2(ehdr->e_ehsize) != sizeof(Elf32_Ehdr) | 261 | if (r2(&ehdr->e_ehsize) != sizeof(Elf32_Ehdr) |
211 | || w2(ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { | 262 | || r2(&ehdr->e_shentsize) != sizeof(Elf32_Shdr)) { |
212 | fprintf(stderr, | 263 | fprintf(stderr, |
213 | "unrecognized ET_EXEC file: %s\n", fname); | 264 | "unrecognized ET_EXEC file: %s\n", fname); |
214 | fail_file(); | 265 | fail_file(); |
215 | } | 266 | } |
216 | do32(ehdr, fname); | 267 | do32(ehdr, fname, custom_sort); |
217 | break; | 268 | break; |
218 | case ELFCLASS64: { | 269 | case ELFCLASS64: { |
219 | Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; | 270 | Elf64_Ehdr *const ghdr = (Elf64_Ehdr *)ehdr; |
220 | if (w2(ghdr->e_ehsize) != sizeof(Elf64_Ehdr) | 271 | if (r2(&ghdr->e_ehsize) != sizeof(Elf64_Ehdr) |
221 | || w2(ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { | 272 | || r2(&ghdr->e_shentsize) != sizeof(Elf64_Shdr)) { |
222 | fprintf(stderr, | 273 | fprintf(stderr, |
223 | "unrecognized ET_EXEC file: %s\n", fname); | 274 | "unrecognized ET_EXEC file: %s\n", fname); |
224 | fail_file(); | 275 | fail_file(); |
225 | } | 276 | } |
226 | do64(ghdr, fname); | 277 | do64(ghdr, fname, custom_sort); |
227 | break; | 278 | break; |
228 | } | 279 | } |
229 | } /* end switch */ | 280 | } /* end switch */ |