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 Side-by-side Diff

... ... @@ -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 }