Commit d59a16836d917548cf41eda3369936684d527f5f

Authored by David Daney
Committed by H. Peter Anvin
1 parent 706276543b

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 Inline Diff

1 ### 1 ###
2 # scripts contains sources for various helper programs used throughout 2 # scripts contains sources for various helper programs used throughout
3 # the kernel for the build process. 3 # the kernel for the build process.
4 # --------------------------------------------------------------------------- 4 # ---------------------------------------------------------------------------
5 # kallsyms: Find all symbols in vmlinux 5 # kallsyms: Find all symbols in vmlinux
6 # pnmttologo: Convert pnm files to logo files 6 # pnmttologo: Convert pnm files to logo files
7 # conmakehash: Create chartable 7 # conmakehash: Create chartable
8 # conmakehash: Create arrays for initializing the kernel console tables 8 # conmakehash: Create arrays for initializing the kernel console tables
9 # docproc: Used in Documentation/DocBook 9 # docproc: Used in Documentation/DocBook
10 10
11 hostprogs-$(CONFIG_KALLSYMS) += kallsyms 11 hostprogs-$(CONFIG_KALLSYMS) += kallsyms
12 hostprogs-$(CONFIG_LOGO) += pnmtologo 12 hostprogs-$(CONFIG_LOGO) += pnmtologo
13 hostprogs-$(CONFIG_VT) += conmakehash 13 hostprogs-$(CONFIG_VT) += conmakehash
14 hostprogs-$(CONFIG_IKCONFIG) += bin2c 14 hostprogs-$(CONFIG_IKCONFIG) += bin2c
15 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount 15 hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
16 hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable 16 hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
17 17
18 HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
19
18 always := $(hostprogs-y) $(hostprogs-m) 20 always := $(hostprogs-y) $(hostprogs-m)
19 21
20 # The following hostprogs-y programs are only build on demand 22 # The following hostprogs-y programs are only build on demand
21 hostprogs-y += unifdef docproc 23 hostprogs-y += unifdef docproc
22 24
23 # These targets are used internally to avoid "is up to date" messages 25 # These targets are used internally to avoid "is up to date" messages
24 PHONY += build_unifdef 26 PHONY += build_unifdef
25 build_unifdef: scripts/unifdef FORCE 27 build_unifdef: scripts/unifdef FORCE
26 @: 28 @:
27 build_docproc: scripts/docproc FORCE 29 build_docproc: scripts/docproc FORCE
28 @: 30 @:
29 31
30 subdir-$(CONFIG_MODVERSIONS) += genksyms 32 subdir-$(CONFIG_MODVERSIONS) += genksyms
31 subdir-y += mod 33 subdir-y += mod
32 subdir-$(CONFIG_SECURITY_SELINUX) += selinux 34 subdir-$(CONFIG_SECURITY_SELINUX) += selinux
33 subdir-$(CONFIG_DTC) += dtc 35 subdir-$(CONFIG_DTC) += dtc
34 36
35 # Let clean descend into subdirs 37 # Let clean descend into subdirs
36 subdir- += basic kconfig package selinux 38 subdir- += basic kconfig package selinux
37 39
scripts/sortextable.c
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 *
8 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. 8 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
9 * Licensed under the GNU General Public License, version 2 (GPLv2). 9 * Licensed under the GNU General Public License, version 2 (GPLv2).
10 * 10 *
11 * Restructured to fit Linux format, as well as other updates: 11 * Restructured to fit Linux format, as well as other updates:
12 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 12 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
13 */ 13 */
14 14
15 /* 15 /*
16 * Strategy: alter the vmlinux file in-place. 16 * Strategy: alter the vmlinux file in-place.
17 */ 17 */
18 18
19 #include <sys/types.h> 19 #include <sys/types.h>
20 #include <sys/mman.h> 20 #include <sys/mman.h>
21 #include <sys/stat.h> 21 #include <sys/stat.h>
22 #include <getopt.h> 22 #include <getopt.h>
23 #include <elf.h> 23 #include <elf.h>
24 #include <fcntl.h> 24 #include <fcntl.h>
25 #include <setjmp.h> 25 #include <setjmp.h>
26 #include <stdio.h> 26 #include <stdio.h>
27 #include <stdlib.h> 27 #include <stdlib.h>
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 */
34 static struct stat sb; /* Remember .st_size, etc. */ 37 static struct stat sb; /* Remember .st_size, etc. */
35 static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */ 38 static jmp_buf jmpenv; /* setjmp/longjmp per-file error escape */
36 39
37 /* setjmp() return values */ 40 /* setjmp() return values */
38 enum { 41 enum {
39 SJ_SETJMP = 0, /* hardwired first return */ 42 SJ_SETJMP = 0, /* hardwired first return */
40 SJ_FAIL, 43 SJ_FAIL,
41 SJ_SUCCEED 44 SJ_SUCCEED
42 }; 45 };
43 46
44 /* Per-file resource cleanup when multiple files. */ 47 /* Per-file resource cleanup when multiple files. */
45 static void 48 static void
46 cleanup(void) 49 cleanup(void)
47 { 50 {
48 if (!mmap_failed) 51 if (!mmap_failed)
49 munmap(ehdr_curr, sb.st_size); 52 munmap(ehdr_curr, sb.st_size);
50 close(fd_map); 53 close(fd_map);
51 } 54 }
52 55
53 static void __attribute__((noreturn)) 56 static void __attribute__((noreturn))
54 fail_file(void) 57 fail_file(void)
55 { 58 {
56 cleanup(); 59 cleanup();
57 longjmp(jmpenv, SJ_FAIL); 60 longjmp(jmpenv, SJ_FAIL);
58 } 61 }
59 62
60 static void __attribute__((noreturn)) 63 static void __attribute__((noreturn))
61 succeed_file(void) 64 succeed_file(void)
62 { 65 {
63 cleanup(); 66 cleanup();
64 longjmp(jmpenv, SJ_SUCCEED); 67 longjmp(jmpenv, SJ_SUCCEED);
65 } 68 }
66 69
67 70
68 /* 71 /*
69 * Get the whole file as a programming convenience in order to avoid 72 * Get the whole file as a programming convenience in order to avoid
70 * malloc+lseek+read+free of many pieces. If successful, then mmap 73 * malloc+lseek+read+free of many pieces. If successful, then mmap
71 * avoids copying unused pieces; else just read the whole file. 74 * avoids copying unused pieces; else just read the whole file.
72 * Open for both read and write. 75 * Open for both read and write.
73 */ 76 */
74 static void *mmap_file(char const *fname) 77 static void *mmap_file(char const *fname)
75 { 78 {
76 void *addr; 79 void *addr;
77 80
78 fd_map = open(fname, O_RDWR); 81 fd_map = open(fname, O_RDWR);
79 if (fd_map < 0 || fstat(fd_map, &sb) < 0) { 82 if (fd_map < 0 || fstat(fd_map, &sb) < 0) {
80 perror(fname); 83 perror(fname);
81 fail_file(); 84 fail_file();
82 } 85 }
83 if (!S_ISREG(sb.st_mode)) { 86 if (!S_ISREG(sb.st_mode)) {
84 fprintf(stderr, "not a regular file: %s\n", fname); 87 fprintf(stderr, "not a regular file: %s\n", fname);
85 fail_file(); 88 fail_file();
86 } 89 }
87 addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, 90 addr = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED,
88 fd_map, 0); 91 fd_map, 0);
89 if (addr == MAP_FAILED) { 92 if (addr == MAP_FAILED) {
90 mmap_failed = 1; 93 mmap_failed = 1;
91 fprintf(stderr, "Could not mmap file: %s\n", fname); 94 fprintf(stderr, "Could not mmap file: %s\n", fname);
92 fail_file(); 95 fail_file();
93 } 96 }
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)
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); 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);
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 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;
200 break; 249 break;
250 case EM_MIPS:
251 break;
201 } /* end switch */ 252 } /* end switch */
202 253
203 switch (ehdr->e_ident[EI_CLASS]) { 254 switch (ehdr->e_ident[EI_CLASS]) {
204 default: 255 default:
205 fprintf(stderr, "unrecognized ELF class %d %s\n", 256 fprintf(stderr, "unrecognized ELF class %d %s\n",
206 ehdr->e_ident[EI_CLASS], fname); 257 ehdr->e_ident[EI_CLASS], 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 */
230 281
231 cleanup(); 282 cleanup();
232 } 283 }
233 284
234 int 285 int
235 main(int argc, char *argv[]) 286 main(int argc, char *argv[])
236 { 287 {
237 int n_error = 0; /* gcc-4.3.0 false positive complaint */ 288 int n_error = 0; /* gcc-4.3.0 false positive complaint */
238 int i; 289 int i;
239 290
240 if (argc < 2) { 291 if (argc < 2) {
241 fprintf(stderr, "usage: sortextable vmlinux...\n"); 292 fprintf(stderr, "usage: sortextable vmlinux...\n");
242 return 0; 293 return 0;
243 } 294 }
244 295
245 /* Process each file in turn, allowing deep failure. */ 296 /* Process each file in turn, allowing deep failure. */
246 for (i = 1; i < argc; i++) { 297 for (i = 1; i < argc; i++) {
247 char *file = argv[i]; 298 char *file = argv[i];
248 int const sjval = setjmp(jmpenv); 299 int const sjval = setjmp(jmpenv);
249 300
250 switch (sjval) { 301 switch (sjval) {
scripts/sortextable.h
1 /* 1 /*
2 * sortextable.h 2 * sortextable.h
3 * 3 *
4 * Copyright 2011 Cavium, Inc. 4 * Copyright 2011 - 2012 Cavium, Inc.
5 * 5 *
6 * Some of this code was taken out of recordmcount.h written by: 6 * Some of this code was taken out of recordmcount.h written by:
7 * 7 *
8 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved. 8 * Copyright 2009 John F. Reiser <jreiser@BitWagon.com>. All rights reserved.
9 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc. 9 * Copyright 2010 Steven Rostedt <srostedt@redhat.com>, Red Hat Inc.
10 * 10 *
11 * 11 *
12 * Licensed under the GNU General Public License, version 2 (GPLv2). 12 * Licensed under the GNU General Public License, version 2 (GPLv2).
13 */ 13 */
14 14
15 #undef extable_ent_size 15 #undef extable_ent_size
16 #undef compare_extable 16 #undef compare_extable
17 #undef do_func 17 #undef do_func
18 #undef Elf_Addr 18 #undef Elf_Addr
19 #undef Elf_Ehdr 19 #undef Elf_Ehdr
20 #undef Elf_Shdr 20 #undef Elf_Shdr
21 #undef Elf_Rel 21 #undef Elf_Rel
22 #undef Elf_Rela 22 #undef Elf_Rela
23 #undef Elf_Sym 23 #undef Elf_Sym
24 #undef ELF_R_SYM 24 #undef ELF_R_SYM
25 #undef Elf_r_sym 25 #undef Elf_r_sym
26 #undef ELF_R_INFO 26 #undef ELF_R_INFO
27 #undef Elf_r_info 27 #undef Elf_r_info
28 #undef ELF_ST_BIND 28 #undef ELF_ST_BIND
29 #undef ELF_ST_TYPE 29 #undef ELF_ST_TYPE
30 #undef fn_ELF_R_SYM 30 #undef fn_ELF_R_SYM
31 #undef fn_ELF_R_INFO 31 #undef fn_ELF_R_INFO
32 #undef uint_t 32 #undef uint_t
33 #undef _r
33 #undef _w 34 #undef _w
34 35
35 #ifdef SORTEXTABLE_64 36 #ifdef SORTEXTABLE_64
36 # define extable_ent_size 16 37 # define extable_ent_size 16
37 # define compare_extable compare_extable_64 38 # define compare_extable compare_extable_64
38 # define do_func do64 39 # define do_func do64
39 # define Elf_Addr Elf64_Addr 40 # define Elf_Addr Elf64_Addr
40 # define Elf_Ehdr Elf64_Ehdr 41 # define Elf_Ehdr Elf64_Ehdr
41 # define Elf_Shdr Elf64_Shdr 42 # define Elf_Shdr Elf64_Shdr
42 # define Elf_Rel Elf64_Rel 43 # define Elf_Rel Elf64_Rel
43 # define Elf_Rela Elf64_Rela 44 # define Elf_Rela Elf64_Rela
44 # define Elf_Sym Elf64_Sym 45 # define Elf_Sym Elf64_Sym
45 # define ELF_R_SYM ELF64_R_SYM 46 # define ELF_R_SYM ELF64_R_SYM
46 # define Elf_r_sym Elf64_r_sym 47 # define Elf_r_sym Elf64_r_sym
47 # define ELF_R_INFO ELF64_R_INFO 48 # define ELF_R_INFO ELF64_R_INFO
48 # define Elf_r_info Elf64_r_info 49 # define Elf_r_info Elf64_r_info
49 # define ELF_ST_BIND ELF64_ST_BIND 50 # define ELF_ST_BIND ELF64_ST_BIND
50 # define ELF_ST_TYPE ELF64_ST_TYPE 51 # define ELF_ST_TYPE ELF64_ST_TYPE
51 # define fn_ELF_R_SYM fn_ELF64_R_SYM 52 # define fn_ELF_R_SYM fn_ELF64_R_SYM
52 # define fn_ELF_R_INFO fn_ELF64_R_INFO 53 # define fn_ELF_R_INFO fn_ELF64_R_INFO
53 # define uint_t uint64_t 54 # define uint_t uint64_t
55 # define _r r8
54 # define _w w8 56 # define _w w8
55 #else 57 #else
56 # define extable_ent_size 8 58 # define extable_ent_size 8
57 # define compare_extable compare_extable_32 59 # define compare_extable compare_extable_32
58 # define do_func do32 60 # define do_func do32
59 # define Elf_Addr Elf32_Addr 61 # define Elf_Addr Elf32_Addr
60 # define Elf_Ehdr Elf32_Ehdr 62 # define Elf_Ehdr Elf32_Ehdr
61 # define Elf_Shdr Elf32_Shdr 63 # define Elf_Shdr Elf32_Shdr
62 # define Elf_Rel Elf32_Rel 64 # define Elf_Rel Elf32_Rel
63 # define Elf_Rela Elf32_Rela 65 # define Elf_Rela Elf32_Rela
64 # define Elf_Sym Elf32_Sym 66 # define Elf_Sym Elf32_Sym
65 # define ELF_R_SYM ELF32_R_SYM 67 # define ELF_R_SYM ELF32_R_SYM
66 # define Elf_r_sym Elf32_r_sym 68 # define Elf_r_sym Elf32_r_sym
67 # define ELF_R_INFO ELF32_R_INFO 69 # define ELF_R_INFO ELF32_R_INFO
68 # define Elf_r_info Elf32_r_info 70 # define Elf_r_info Elf32_r_info
69 # define ELF_ST_BIND ELF32_ST_BIND 71 # define ELF_ST_BIND ELF32_ST_BIND
70 # define ELF_ST_TYPE ELF32_ST_TYPE 72 # define ELF_ST_TYPE ELF32_ST_TYPE
71 # define fn_ELF_R_SYM fn_ELF32_R_SYM 73 # define fn_ELF_R_SYM fn_ELF32_R_SYM
72 # define fn_ELF_R_INFO fn_ELF32_R_INFO 74 # define fn_ELF_R_INFO fn_ELF32_R_INFO
73 # define uint_t uint32_t 75 # define uint_t uint32_t
76 # define _r r
74 # define _w w 77 # define _w w
75 #endif 78 #endif
76 79
77 static int compare_extable(const void *a, const void *b) 80 static int compare_extable(const void *a, const void *b)
78 { 81 {
79 const uint_t *aa = a; 82 Elf_Addr av = _r(a);
80 const uint_t *bb = b; 83 Elf_Addr bv = _r(b);
81 84
82 if (_w(*aa) < _w(*bb)) 85 if (av < bv)
83 return -1; 86 return -1;
84 if (_w(*aa) > _w(*bb)) 87 if (av > bv)
85 return 1; 88 return 1;
86 return 0; 89 return 0;
87 } 90 }
88 91
89 static void 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 Elf_Shdr *shdr; 95 Elf_Shdr *shdr;
93 Elf_Shdr *shstrtab_sec; 96 Elf_Shdr *shstrtab_sec;
94 Elf_Shdr *strtab_sec = NULL; 97 Elf_Shdr *strtab_sec = NULL;
95 Elf_Shdr *symtab_sec = NULL; 98 Elf_Shdr *symtab_sec = NULL;
96 Elf_Shdr *extab_sec = NULL; 99 Elf_Shdr *extab_sec = NULL;
97 Elf_Sym *sym; 100 Elf_Sym *sym;
98 Elf_Sym *sort_needed_sym; 101 Elf_Sym *sort_needed_sym;
99 Elf_Shdr *sort_needed_sec; 102 Elf_Shdr *sort_needed_sec;
103 Elf_Rel *relocs = NULL;
104 int relocs_size;
100 uint32_t *sort_done_location; 105 uint32_t *sort_done_location;
101 const char *secstrtab; 106 const char *secstrtab;
102 const char *strtab; 107 const char *strtab;
108 char *extab_image;
109 int extab_index = 0;
103 int i; 110 int i;
104 int idx; 111 int idx;
105 112
106 shdr = (Elf_Shdr *)((void *)ehdr + _w(ehdr->e_shoff)); 113 shdr = (Elf_Shdr *)((char *)ehdr + _r(&ehdr->e_shoff));
107 shstrtab_sec = shdr + w2(ehdr->e_shstrndx); 114 shstrtab_sec = shdr + r2(&ehdr->e_shstrndx);
108 secstrtab = (const char *)ehdr + _w(shstrtab_sec->sh_offset); 115 secstrtab = (const char *)ehdr + _r(&shstrtab_sec->sh_offset);
109 for (i = 0; i < w2(ehdr->e_shnum); i++) { 116 for (i = 0; i < r2(&ehdr->e_shnum); i++) {
110 idx = w(shdr[i].sh_name); 117 idx = r(&shdr[i].sh_name);
111 if (strcmp(secstrtab + idx, "__ex_table") == 0) 118 if (strcmp(secstrtab + idx, "__ex_table") == 0) {
112 extab_sec = shdr + i; 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 if (strcmp(secstrtab + idx, ".symtab") == 0) 128 if (strcmp(secstrtab + idx, ".symtab") == 0)
114 symtab_sec = shdr + i; 129 symtab_sec = shdr + i;
115 if (strcmp(secstrtab + idx, ".strtab") == 0) 130 if (strcmp(secstrtab + idx, ".strtab") == 0)
116 strtab_sec = shdr + i; 131 strtab_sec = shdr + i;
117 } 132 }
118 if (strtab_sec == NULL) { 133 if (strtab_sec == NULL) {
119 fprintf(stderr, "no .strtab in file: %s\n", fname); 134 fprintf(stderr, "no .strtab in file: %s\n", fname);
120 fail_file(); 135 fail_file();
121 } 136 }
122 if (symtab_sec == NULL) { 137 if (symtab_sec == NULL) {
123 fprintf(stderr, "no .symtab in file: %s\n", fname); 138 fprintf(stderr, "no .symtab in file: %s\n", fname);
124 fail_file(); 139 fail_file();
125 } 140 }
126 if (extab_sec == NULL) { 141 if (extab_sec == NULL) {
127 fprintf(stderr, "no __ex_table in file: %s\n", fname); 142 fprintf(stderr, "no __ex_table in file: %s\n", fname);
128 fail_file(); 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 */ 147 extab_image = (void *)ehdr + _r(&extab_sec->sh_offset);
133 qsort((void *)ehdr + _w(extab_sec->sh_offset),
134 (_w(extab_sec->sh_size) / extable_ent_size),
135 extable_ent_size, compare_extable);
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 /* find main_extable_sort_needed */ 160 /* find main_extable_sort_needed */
138 sort_needed_sym = NULL; 161 sort_needed_sym = NULL;
139 for (i = 0; i < _w(symtab_sec->sh_size) / sizeof(Elf_Sym); i++) { 162 for (i = 0; i < _r(&symtab_sec->sh_size) / sizeof(Elf_Sym); i++) {
140 sym = (void *)ehdr + _w(symtab_sec->sh_offset); 163 sym = (void *)ehdr + _r(&symtab_sec->sh_offset);
141 sym += i; 164 sym += i;
142 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) 165 if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
143 continue; 166 continue;
144 idx = w(sym->st_name); 167 idx = r(&sym->st_name);
145 if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) { 168 if (strcmp(strtab + idx, "main_extable_sort_needed") == 0) {
146 sort_needed_sym = sym; 169 sort_needed_sym = sym;
147 break; 170 break;
148 } 171 }
149 } 172 }
150 if (sort_needed_sym == NULL) { 173 if (sort_needed_sym == NULL) {
151 fprintf(stderr, 174 fprintf(stderr,
152 "no main_extable_sort_needed symbol in file: %s\n", 175 "no main_extable_sort_needed symbol in file: %s\n",
153 fname); 176 fname);
154 fail_file(); 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 sort_done_location = (void *)ehdr + 180 sort_done_location = (void *)ehdr +
158 _w(sort_needed_sec->sh_offset) + 181 _r(&sort_needed_sec->sh_offset) +
159 _w(sort_needed_sym->st_value) - 182 _r(&sort_needed_sym->st_value) -
160 _w(sort_needed_sec->sh_addr); 183 _r(&sort_needed_sec->sh_addr);
161 184
185 #if 1
162 printf("sort done marker at %lx\n", 186 printf("sort done marker at %lx\n",
163 (unsigned long) (_w(sort_needed_sec->sh_offset) + 187 (unsigned long)((char *)sort_done_location - (char *)ehdr));
164 _w(sort_needed_sym->st_value) - 188 #endif
165 _w(sort_needed_sec->sh_addr)));