aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Daney <david.daney@cavium.com>2012-04-24 14:23:14 -0400
committerH. Peter Anvin <hpa@zytor.com>2012-04-24 14:42:20 -0400
commitd59a16836d917548cf41eda3369936684d527f5f (patch)
treea332ee65290db2a53fb3cfca6e97de2a622c3df6
parent706276543b699d80f546e45f8b12574e7b18d952 (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>
-rw-r--r--scripts/Makefile2
-rw-r--r--scripts/sortextable.c171
-rw-r--r--scripts/sortextable.h79
3 files changed, 164 insertions, 88 deletions
diff --git a/scripts/Makefile b/scripts/Makefile
index 43e19b9fc641..9eace52c64df 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -15,6 +15,8 @@ hostprogs-$(CONFIG_IKCONFIG) += bin2c
15hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount 15hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount
16hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable 16hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable
17 17
18HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
19
18always := $(hostprogs-y) $(hostprogs-m) 20always := $(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
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
31static int fd_map; /* File descriptor for file being modified. */ 34static int fd_map; /* File descriptor for file being modified. */
32static int mmap_failed; /* Boolean flag. */ 35static int mmap_failed; /* Boolean flag. */
33static void *ehdr_curr; /* current ElfXX_Ehdr * for resource cleanup */ 36static 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. */ 100static uint64_t r8be(const uint64_t *x)
98
99static 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 104static uint32_t rbe(const uint32_t *x)
111static 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 108static uint16_t r2be(const uint16_t *x)
119static 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 112static uint64_t r8le(const uint64_t *x)
125static uint64_t w8nat(uint64_t const x)
126{ 113{
127 return x; 114 return get_unaligned_le64(x);
128} 115}
129 116static uint32_t rle(const uint32_t *x)
130static uint32_t w4nat(uint32_t const x) 117{
118 return get_unaligned_le32(x);
119}
120static uint16_t r2le(const uint16_t *x)
131{ 121{
132 return x; 122 return get_unaligned_le16(x);
133} 123}
134 124
135static uint32_t w2nat(uint16_t const x) 125static void w8be(uint64_t val, uint64_t *x)
126{
127 put_unaligned_be64(val, x);
128}
129static void wbe(uint32_t val, uint32_t *x)
130{
131 put_unaligned_be32(val, x);
132}
133static void w2be(uint16_t val, uint16_t *x)
134{
135 put_unaligned_be16(val, x);
136}
137static void w8le(uint64_t val, uint64_t *x)
138{
139 put_unaligned_le64(val, x);
140}
141static void wle(uint32_t val, uint32_t *x)
142{
143 put_unaligned_le32(val, x);
144}
145static void w2le(uint16_t val, uint16_t *x)
136{ 146{
137 return x; 147 put_unaligned_le16(val, x);
138} 148}
139 149
140static uint64_t (*w8)(uint64_t); 150static uint64_t (*r8)(const uint64_t *);
141static uint32_t (*w)(uint32_t); 151static uint32_t (*r)(const uint32_t *);
142static uint32_t (*w2)(uint16_t); 152static uint16_t (*r2)(const uint16_t *);
153static void (*w8)(uint64_t, uint64_t *);
154static void (*w)(uint32_t, uint32_t *);
155static void (*w2)(uint16_t, uint16_t *);
143 156
157typedef 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
164static 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
176static 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
151static void 202static void
152do_file(char const *const fname) 203do_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 */
diff --git a/scripts/sortextable.h b/scripts/sortextable.h
index bb6aaf166002..e4fd45b7e456 100644
--- a/scripts/sortextable.h
+++ b/scripts/sortextable.h
@@ -1,7 +1,7 @@
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 *
@@ -30,6 +30,7 @@
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
@@ -51,6 +52,7 @@
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
@@ -71,23 +73,24 @@
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
77static int compare_extable(const void *a, const void *b) 80static 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
89static void 92static void
90do_func(Elf_Ehdr *const ehdr, char const *const fname) 93do_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;
@@ -97,19 +100,31 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname)
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)
@@ -127,21 +142,29 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname)
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), 148
134 (_w(extab_sec->sh_size) / extable_ent_size), 149 if (custom_sort) {
135 extable_ent_size, compare_extable); 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);
136 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;
@@ -153,16 +176,16 @@ do_func(Elf_Ehdr *const ehdr, char const *const fname)
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)));
166 /* We sorted it, clear the flag. */ 189 /* We sorted it, clear the flag. */
167 *sort_done_location = 0; 190 w(0, sort_done_location);
168} 191}