hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/tools/objtool/elf.c
....@@ -1,22 +1,10 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * elf.c - ELF access library
34 *
45 * Adapted from kpatch (https://github.com/dynup/kpatch):
56 * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
67 * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
7
- *
8
- * This program is free software; you can redistribute it and/or
9
- * modify it under the terms of the GNU General Public License
10
- * as published by the Free Software Foundation; either version 2
11
- * of the License, or (at your option) any later version.
12
- *
13
- * This program is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
17
- *
18
- * You should have received a copy of the GNU General Public License
19
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
208 */
219
2210 #include <sys/types.h>
....@@ -27,17 +15,123 @@
2715 #include <string.h>
2816 #include <unistd.h>
2917 #include <errno.h>
18
+#include "builtin.h"
3019
3120 #include "elf.h"
3221 #include "warn.h"
3322
3423 #define MAX_NAME_LEN 128
3524
36
-struct section *find_section_by_name(struct elf *elf, const char *name)
25
+static inline u32 str_hash(const char *str)
26
+{
27
+ return jhash(str, strlen(str), 0);
28
+}
29
+
30
+static inline int elf_hash_bits(void)
31
+{
32
+ return vmlinux ? ELF_HASH_BITS : 16;
33
+}
34
+
35
+#define elf_hash_add(hashtable, node, key) \
36
+ hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())])
37
+
38
+static void elf_hash_init(struct hlist_head *table)
39
+{
40
+ __hash_init(table, 1U << elf_hash_bits());
41
+}
42
+
43
+#define elf_hash_for_each_possible(name, obj, member, key) \
44
+ hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member)
45
+
46
+static void rb_add(struct rb_root *tree, struct rb_node *node,
47
+ int (*cmp)(struct rb_node *, const struct rb_node *))
48
+{
49
+ struct rb_node **link = &tree->rb_node;
50
+ struct rb_node *parent = NULL;
51
+
52
+ while (*link) {
53
+ parent = *link;
54
+ if (cmp(node, parent) < 0)
55
+ link = &parent->rb_left;
56
+ else
57
+ link = &parent->rb_right;
58
+ }
59
+
60
+ rb_link_node(node, parent, link);
61
+ rb_insert_color(node, tree);
62
+}
63
+
64
+static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key,
65
+ int (*cmp)(const void *key, const struct rb_node *))
66
+{
67
+ struct rb_node *node = tree->rb_node;
68
+ struct rb_node *match = NULL;
69
+
70
+ while (node) {
71
+ int c = cmp(key, node);
72
+ if (c <= 0) {
73
+ if (!c)
74
+ match = node;
75
+ node = node->rb_left;
76
+ } else if (c > 0) {
77
+ node = node->rb_right;
78
+ }
79
+ }
80
+
81
+ return match;
82
+}
83
+
84
+static struct rb_node *rb_next_match(struct rb_node *node, const void *key,
85
+ int (*cmp)(const void *key, const struct rb_node *))
86
+{
87
+ node = rb_next(node);
88
+ if (node && cmp(key, node))
89
+ node = NULL;
90
+ return node;
91
+}
92
+
93
+#define rb_for_each(tree, node, key, cmp) \
94
+ for ((node) = rb_find_first((tree), (key), (cmp)); \
95
+ (node); (node) = rb_next_match((node), (key), (cmp)))
96
+
97
+static int symbol_to_offset(struct rb_node *a, const struct rb_node *b)
98
+{
99
+ struct symbol *sa = rb_entry(a, struct symbol, node);
100
+ struct symbol *sb = rb_entry(b, struct symbol, node);
101
+
102
+ if (sa->offset < sb->offset)
103
+ return -1;
104
+ if (sa->offset > sb->offset)
105
+ return 1;
106
+
107
+ if (sa->len < sb->len)
108
+ return -1;
109
+ if (sa->len > sb->len)
110
+ return 1;
111
+
112
+ sa->alias = sb;
113
+
114
+ return 0;
115
+}
116
+
117
+static int symbol_by_offset(const void *key, const struct rb_node *node)
118
+{
119
+ const struct symbol *s = rb_entry(node, struct symbol, node);
120
+ const unsigned long *o = key;
121
+
122
+ if (*o < s->offset)
123
+ return -1;
124
+ if (*o >= s->offset + s->len)
125
+ return 1;
126
+
127
+ return 0;
128
+}
129
+
130
+struct section *find_section_by_name(const struct elf *elf, const char *name)
37131 {
38132 struct section *sec;
39133
40
- list_for_each_entry(sec, &elf->sections, list)
134
+ elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
41135 if (!strcmp(sec->name, name))
42136 return sec;
43137
....@@ -49,7 +143,7 @@
49143 {
50144 struct section *sec;
51145
52
- list_for_each_entry(sec, &elf->sections, list)
146
+ elf_hash_for_each_possible(elf->section_hash, sec, hash, idx)
53147 if (sec->idx == idx)
54148 return sec;
55149
....@@ -58,86 +152,114 @@
58152
59153 static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
60154 {
61
- struct section *sec;
62155 struct symbol *sym;
63156
64
- list_for_each_entry(sec, &elf->sections, list)
65
- hash_for_each_possible(sec->symbol_hash, sym, hash, idx)
66
- if (sym->idx == idx)
67
- return sym;
157
+ elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
158
+ if (sym->idx == idx)
159
+ return sym;
68160
69161 return NULL;
70162 }
71163
72164 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
73165 {
166
+ struct rb_node *node;
167
+
168
+ rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
169
+ struct symbol *s = rb_entry(node, struct symbol, node);
170
+
171
+ if (s->offset == offset && s->type != STT_SECTION)
172
+ return s;
173
+ }
174
+
175
+ return NULL;
176
+}
177
+
178
+struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)
179
+{
180
+ struct rb_node *node;
181
+
182
+ rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
183
+ struct symbol *s = rb_entry(node, struct symbol, node);
184
+
185
+ if (s->offset == offset && s->type == STT_FUNC)
186
+ return s;
187
+ }
188
+
189
+ return NULL;
190
+}
191
+
192
+struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset)
193
+{
194
+ struct rb_node *node;
195
+
196
+ rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
197
+ struct symbol *s = rb_entry(node, struct symbol, node);
198
+
199
+ if (s->type != STT_SECTION)
200
+ return s;
201
+ }
202
+
203
+ return NULL;
204
+}
205
+
206
+struct symbol *find_func_containing(struct section *sec, unsigned long offset)
207
+{
208
+ struct rb_node *node;
209
+
210
+ rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
211
+ struct symbol *s = rb_entry(node, struct symbol, node);
212
+
213
+ if (s->type == STT_FUNC)
214
+ return s;
215
+ }
216
+
217
+ return NULL;
218
+}
219
+
220
+struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
221
+{
74222 struct symbol *sym;
75223
76
- list_for_each_entry(sym, &sec->symbol_list, list)
77
- if (sym->type != STT_SECTION &&
78
- sym->offset == offset)
224
+ elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
225
+ if (!strcmp(sym->name, name))
79226 return sym;
80227
81228 return NULL;
82229 }
83230
84
-struct symbol *find_symbol_by_name(struct elf *elf, const char *name)
231
+struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
232
+ unsigned long offset, unsigned int len)
85233 {
86
- struct section *sec;
87
- struct symbol *sym;
88
-
89
- list_for_each_entry(sec, &elf->sections, list)
90
- list_for_each_entry(sym, &sec->symbol_list, list)
91
- if (!strcmp(sym->name, name))
92
- return sym;
93
-
94
- return NULL;
95
-}
96
-
97
-struct symbol *find_symbol_containing(struct section *sec, unsigned long offset)
98
-{
99
- struct symbol *sym;
100
-
101
- list_for_each_entry(sym, &sec->symbol_list, list)
102
- if (sym->type != STT_SECTION &&
103
- offset >= sym->offset && offset < sym->offset + sym->len)
104
- return sym;
105
-
106
- return NULL;
107
-}
108
-
109
-struct rela *find_rela_by_dest_range(struct section *sec, unsigned long offset,
110
- unsigned int len)
111
-{
112
- struct rela *rela;
234
+ struct reloc *reloc, *r = NULL;
113235 unsigned long o;
114236
115
- if (!sec->rela)
237
+ if (!sec->reloc)
116238 return NULL;
117239
118
- for (o = offset; o < offset + len; o++)
119
- hash_for_each_possible(sec->rela->rela_hash, rela, hash, o)
120
- if (rela->offset == o)
121
- return rela;
240
+ sec = sec->reloc;
241
+
242
+ for_offset_range(o, offset, offset + len) {
243
+ elf_hash_for_each_possible(elf->reloc_hash, reloc, hash,
244
+ sec_offset_hash(sec, o)) {
245
+ if (reloc->sec != sec)
246
+ continue;
247
+
248
+ if (reloc->offset >= offset && reloc->offset < offset + len) {
249
+ if (!r || reloc->offset < r->offset)
250
+ r = reloc;
251
+ }
252
+ }
253
+ if (r)
254
+ return r;
255
+ }
122256
123257 return NULL;
124258 }
125259
126
-struct rela *find_rela_by_dest(struct section *sec, unsigned long offset)
260
+struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
127261 {
128
- return find_rela_by_dest_range(sec, offset, 1);
129
-}
130
-
131
-struct symbol *find_containing_func(struct section *sec, unsigned long offset)
132
-{
133
- struct symbol *func;
134
-
135
- list_for_each_entry(func, &sec->symbol_list, list)
136
- if (func->type == STT_FUNC && offset >= func->offset &&
137
- offset < func->offset + func->len)
138
- return func;
139
-
140
- return NULL;
262
+ return find_reloc_by_dest_range(elf, sec, offset, 1);
141263 }
142264
143265 static int read_sections(struct elf *elf)
....@@ -166,11 +288,7 @@
166288 memset(sec, 0, sizeof(*sec));
167289
168290 INIT_LIST_HEAD(&sec->symbol_list);
169
- INIT_LIST_HEAD(&sec->rela_list);
170
- hash_init(sec->rela_hash);
171
- hash_init(sec->symbol_hash);
172
-
173
- list_add_tail(&sec->list, &elf->sections);
291
+ INIT_LIST_HEAD(&sec->reloc_list);
174292
175293 s = elf_getscn(elf->elf, i);
176294 if (!s) {
....@@ -205,7 +323,14 @@
205323 }
206324 }
207325 sec->len = sec->sh.sh_size;
326
+
327
+ list_add_tail(&sec->list, &elf->sections);
328
+ elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
329
+ elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
208330 }
331
+
332
+ if (stats)
333
+ printf("nr_sections: %lu\n", (unsigned long)sections_nr);
209334
210335 /* sanity check, one more call to elf_nextscn() should return NULL */
211336 if (elf_nextscn(elf->elf, s)) {
....@@ -216,13 +341,45 @@
216341 return 0;
217342 }
218343
344
+static void elf_add_symbol(struct elf *elf, struct symbol *sym)
345
+{
346
+ struct list_head *entry;
347
+ struct rb_node *pnode;
348
+
349
+ sym->alias = sym;
350
+
351
+ sym->type = GELF_ST_TYPE(sym->sym.st_info);
352
+ sym->bind = GELF_ST_BIND(sym->sym.st_info);
353
+
354
+ sym->offset = sym->sym.st_value;
355
+ sym->len = sym->sym.st_size;
356
+
357
+ rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset);
358
+ pnode = rb_prev(&sym->node);
359
+ if (pnode)
360
+ entry = &rb_entry(pnode, struct symbol, node)->list;
361
+ else
362
+ entry = &sym->sec->symbol_list;
363
+ list_add(&sym->list, entry);
364
+ elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
365
+ elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
366
+
367
+ /*
368
+ * Don't store empty STT_NOTYPE symbols in the rbtree. They
369
+ * can exist within a function, confusing the sorting.
370
+ */
371
+ if (!sym->len)
372
+ rb_erase(&sym->node, &sym->sec->symbol_tree);
373
+}
374
+
219375 static int read_symbols(struct elf *elf)
220376 {
221
- struct section *symtab, *sec;
377
+ struct section *symtab, *symtab_shndx, *sec;
222378 struct symbol *sym, *pfunc;
223
- struct list_head *entry, *tmp;
224379 int symbols_nr, i;
225380 char *coldstr;
381
+ Elf_Data *shndx_data = NULL;
382
+ Elf32_Word shndx;
226383
227384 symtab = find_section_by_name(elf, ".symtab");
228385 if (!symtab) {
....@@ -232,6 +389,10 @@
232389 */
233390 return 0;
234391 }
392
+
393
+ symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
394
+ if (symtab_shndx)
395
+ shndx_data = symtab_shndx->data;
235396
236397 symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
237398
....@@ -245,8 +406,9 @@
245406
246407 sym->idx = i;
247408
248
- if (!gelf_getsym(symtab->data, i, &sym->sym)) {
249
- WARN_ELF("gelf_getsym");
409
+ if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
410
+ &shndx)) {
411
+ WARN_ELF("gelf_getsymshndx");
250412 goto err;
251413 }
252414
....@@ -257,48 +419,30 @@
257419 goto err;
258420 }
259421
260
- sym->type = GELF_ST_TYPE(sym->sym.st_info);
261
- sym->bind = GELF_ST_BIND(sym->sym.st_info);
422
+ if ((sym->sym.st_shndx > SHN_UNDEF &&
423
+ sym->sym.st_shndx < SHN_LORESERVE) ||
424
+ (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
425
+ if (sym->sym.st_shndx != SHN_XINDEX)
426
+ shndx = sym->sym.st_shndx;
262427
263
- if (sym->sym.st_shndx > SHN_UNDEF &&
264
- sym->sym.st_shndx < SHN_LORESERVE) {
265
- sym->sec = find_section_by_index(elf,
266
- sym->sym.st_shndx);
428
+ sym->sec = find_section_by_index(elf, shndx);
267429 if (!sym->sec) {
268430 WARN("couldn't find section for symbol %s",
269431 sym->name);
270432 goto err;
271433 }
272
- if (sym->type == STT_SECTION) {
434
+ if (GELF_ST_TYPE(sym->sym.st_info) == STT_SECTION) {
273435 sym->name = sym->sec->name;
274436 sym->sec->sym = sym;
275437 }
276438 } else
277439 sym->sec = find_section_by_index(elf, 0);
278440
279
- sym->offset = sym->sym.st_value;
280
- sym->len = sym->sym.st_size;
281
-
282
- /* sorted insert into a per-section list */
283
- entry = &sym->sec->symbol_list;
284
- list_for_each_prev(tmp, &sym->sec->symbol_list) {
285
- struct symbol *s;
286
-
287
- s = list_entry(tmp, struct symbol, list);
288
-
289
- if (sym->offset > s->offset) {
290
- entry = tmp;
291
- break;
292
- }
293
-
294
- if (sym->offset == s->offset && sym->len >= s->len) {
295
- entry = tmp;
296
- break;
297
- }
298
- }
299
- list_add(&sym->list, entry);
300
- hash_add(sym->sec->symbol_hash, &sym->hash, sym->idx);
441
+ elf_add_symbol(elf, sym);
301442 }
443
+
444
+ if (stats)
445
+ printf("nr_symbols: %lu\n", (unsigned long)symbols_nr);
302446
303447 /* Create parent/child links for any cold subfunctions */
304448 list_for_each_entry(sec, &elf->sections, list) {
....@@ -307,7 +451,13 @@
307451 size_t pnamelen;
308452 if (sym->type != STT_FUNC)
309453 continue;
310
- sym->pfunc = sym->cfunc = sym;
454
+
455
+ if (sym->pfunc == NULL)
456
+ sym->pfunc = sym;
457
+
458
+ if (sym->cfunc == NULL)
459
+ sym->cfunc = sym;
460
+
311461 coldstr = strstr(sym->name, ".cold");
312462 if (!coldstr)
313463 continue;
....@@ -355,61 +505,377 @@
355505 return -1;
356506 }
357507
358
-static int read_relas(struct elf *elf)
508
+static struct section *elf_create_reloc_section(struct elf *elf,
509
+ struct section *base,
510
+ int reltype);
511
+
512
+int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
513
+ unsigned int type, struct symbol *sym, s64 addend)
514
+{
515
+ struct reloc *reloc;
516
+
517
+ if (!sec->reloc && !elf_create_reloc_section(elf, sec, SHT_RELA))
518
+ return -1;
519
+
520
+ reloc = malloc(sizeof(*reloc));
521
+ if (!reloc) {
522
+ perror("malloc");
523
+ return -1;
524
+ }
525
+ memset(reloc, 0, sizeof(*reloc));
526
+
527
+ reloc->sec = sec->reloc;
528
+ reloc->offset = offset;
529
+ reloc->type = type;
530
+ reloc->sym = sym;
531
+ reloc->addend = addend;
532
+
533
+ list_add_tail(&reloc->list, &sec->reloc->reloc_list);
534
+ elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
535
+
536
+ sec->reloc->changed = true;
537
+
538
+ return 0;
539
+}
540
+
541
+/*
542
+ * Ensure that any reloc section containing references to @sym is marked
543
+ * changed such that it will get re-generated in elf_rebuild_reloc_sections()
544
+ * with the new symbol index.
545
+ */
546
+static void elf_dirty_reloc_sym(struct elf *elf, struct symbol *sym)
359547 {
360548 struct section *sec;
361
- struct rela *rela;
362
- int i;
363
- unsigned int symndx;
364549
365550 list_for_each_entry(sec, &elf->sections, list) {
366
- if (sec->sh.sh_type != SHT_RELA)
551
+ struct reloc *reloc;
552
+
553
+ if (sec->changed)
367554 continue;
368555
369
- sec->base = find_section_by_name(elf, sec->name + 5);
370
- if (!sec->base) {
371
- WARN("can't find base section for rela section %s",
372
- sec->name);
556
+ list_for_each_entry(reloc, &sec->reloc_list, list) {
557
+ if (reloc->sym == sym) {
558
+ sec->changed = true;
559
+ break;
560
+ }
561
+ }
562
+ }
563
+}
564
+
565
+/*
566
+ * The libelf API is terrible; gelf_update_sym*() takes a data block relative
567
+ * index value, *NOT* the symbol index. As such, iterate the data blocks and
568
+ * adjust index until it fits.
569
+ *
570
+ * If no data block is found, allow adding a new data block provided the index
571
+ * is only one past the end.
572
+ */
573
+static int elf_update_symbol(struct elf *elf, struct section *symtab,
574
+ struct section *symtab_shndx, struct symbol *sym)
575
+{
576
+ Elf32_Word shndx = sym->sec ? sym->sec->idx : SHN_UNDEF;
577
+ Elf_Data *symtab_data = NULL, *shndx_data = NULL;
578
+ Elf64_Xword entsize = symtab->sh.sh_entsize;
579
+ int max_idx, idx = sym->idx;
580
+ Elf_Scn *s, *t = NULL;
581
+ bool is_special_shndx = sym->sym.st_shndx >= SHN_LORESERVE &&
582
+ sym->sym.st_shndx != SHN_XINDEX;
583
+
584
+ if (is_special_shndx)
585
+ shndx = sym->sym.st_shndx;
586
+
587
+ s = elf_getscn(elf->elf, symtab->idx);
588
+ if (!s) {
589
+ WARN_ELF("elf_getscn");
590
+ return -1;
591
+ }
592
+
593
+ if (symtab_shndx) {
594
+ t = elf_getscn(elf->elf, symtab_shndx->idx);
595
+ if (!t) {
596
+ WARN_ELF("elf_getscn");
597
+ return -1;
598
+ }
599
+ }
600
+
601
+ for (;;) {
602
+ /* get next data descriptor for the relevant sections */
603
+ symtab_data = elf_getdata(s, symtab_data);
604
+ if (t)
605
+ shndx_data = elf_getdata(t, shndx_data);
606
+
607
+ /* end-of-list */
608
+ if (!symtab_data) {
609
+ void *buf;
610
+
611
+ if (idx) {
612
+ /* we don't do holes in symbol tables */
613
+ WARN("index out of range");
614
+ return -1;
615
+ }
616
+
617
+ /* if @idx == 0, it's the next contiguous entry, create it */
618
+ symtab_data = elf_newdata(s);
619
+ if (t)
620
+ shndx_data = elf_newdata(t);
621
+
622
+ buf = calloc(1, entsize);
623
+ if (!buf) {
624
+ WARN("malloc");
625
+ return -1;
626
+ }
627
+
628
+ symtab_data->d_buf = buf;
629
+ symtab_data->d_size = entsize;
630
+ symtab_data->d_align = 1;
631
+ symtab_data->d_type = ELF_T_SYM;
632
+
633
+ symtab->sh.sh_size += entsize;
634
+ symtab->changed = true;
635
+
636
+ if (t) {
637
+ shndx_data->d_buf = &sym->sec->idx;
638
+ shndx_data->d_size = sizeof(Elf32_Word);
639
+ shndx_data->d_align = sizeof(Elf32_Word);
640
+ shndx_data->d_type = ELF_T_WORD;
641
+
642
+ symtab_shndx->sh.sh_size += sizeof(Elf32_Word);
643
+ symtab_shndx->changed = true;
644
+ }
645
+
646
+ break;
647
+ }
648
+
649
+ /* empty blocks should not happen */
650
+ if (!symtab_data->d_size) {
651
+ WARN("zero size data");
373652 return -1;
374653 }
375654
376
- sec->base->rela = sec;
655
+ /* is this the right block? */
656
+ max_idx = symtab_data->d_size / entsize;
657
+ if (idx < max_idx)
658
+ break;
377659
378
- for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
379
- rela = malloc(sizeof(*rela));
380
- if (!rela) {
381
- perror("malloc");
382
- return -1;
383
- }
384
- memset(rela, 0, sizeof(*rela));
660
+ /* adjust index and try again */
661
+ idx -= max_idx;
662
+ }
385663
386
- if (!gelf_getrela(sec->data, i, &rela->rela)) {
387
- WARN_ELF("gelf_getrela");
388
- return -1;
389
- }
664
+ /* something went side-ways */
665
+ if (idx < 0) {
666
+ WARN("negative index");
667
+ return -1;
668
+ }
390669
391
- rela->type = GELF_R_TYPE(rela->rela.r_info);
392
- rela->addend = rela->rela.r_addend;
393
- rela->offset = rela->rela.r_offset;
394
- symndx = GELF_R_SYM(rela->rela.r_info);
395
- rela->sym = find_symbol_by_index(elf, symndx);
396
- rela->rela_sec = sec;
397
- if (!rela->sym) {
398
- WARN("can't find rela entry symbol %d for %s",
399
- symndx, sec->name);
400
- return -1;
401
- }
402
-
403
- list_add_tail(&rela->list, &sec->rela_list);
404
- hash_add(sec->rela_hash, &rela->hash, rela->offset);
405
-
670
+ /* setup extended section index magic and write the symbol */
671
+ if ((shndx >= SHN_UNDEF && shndx < SHN_LORESERVE) || is_special_shndx) {
672
+ sym->sym.st_shndx = shndx;
673
+ if (!shndx_data)
674
+ shndx = 0;
675
+ } else {
676
+ sym->sym.st_shndx = SHN_XINDEX;
677
+ if (!shndx_data) {
678
+ WARN("no .symtab_shndx");
679
+ return -1;
406680 }
681
+ }
682
+
683
+ if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)) {
684
+ WARN_ELF("gelf_update_symshndx");
685
+ return -1;
407686 }
408687
409688 return 0;
410689 }
411690
412
-struct elf *elf_open(const char *name, int flags)
691
+static struct symbol *
692
+elf_create_section_symbol(struct elf *elf, struct section *sec)
693
+{
694
+ struct section *symtab, *symtab_shndx;
695
+ Elf32_Word first_non_local, new_idx;
696
+ struct symbol *sym, *old;
697
+
698
+ symtab = find_section_by_name(elf, ".symtab");
699
+ if (symtab) {
700
+ symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
701
+ } else {
702
+ WARN("no .symtab");
703
+ return NULL;
704
+ }
705
+
706
+ sym = calloc(1, sizeof(*sym));
707
+ if (!sym) {
708
+ perror("malloc");
709
+ return NULL;
710
+ }
711
+
712
+ sym->name = sec->name;
713
+ sym->sec = sec;
714
+
715
+ // st_name 0
716
+ sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
717
+ // st_other 0
718
+ // st_value 0
719
+ // st_size 0
720
+
721
+ /*
722
+ * Move the first global symbol, as per sh_info, into a new, higher
723
+ * symbol index. This fees up a spot for a new local symbol.
724
+ */
725
+ first_non_local = symtab->sh.sh_info;
726
+ new_idx = symtab->sh.sh_size / symtab->sh.sh_entsize;
727
+ old = find_symbol_by_index(elf, first_non_local);
728
+ if (old) {
729
+ old->idx = new_idx;
730
+
731
+ hlist_del(&old->hash);
732
+ elf_hash_add(elf->symbol_hash, &old->hash, old->idx);
733
+
734
+ elf_dirty_reloc_sym(elf, old);
735
+
736
+ if (elf_update_symbol(elf, symtab, symtab_shndx, old)) {
737
+ WARN("elf_update_symbol move");
738
+ return NULL;
739
+ }
740
+
741
+ new_idx = first_non_local;
742
+ }
743
+
744
+ sym->idx = new_idx;
745
+ if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) {
746
+ WARN("elf_update_symbol");
747
+ return NULL;
748
+ }
749
+
750
+ /*
751
+ * Either way, we added a LOCAL symbol.
752
+ */
753
+ symtab->sh.sh_info += 1;
754
+
755
+ elf_add_symbol(elf, sym);
756
+
757
+ return sym;
758
+}
759
+
760
+int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
761
+ unsigned long offset, unsigned int type,
762
+ struct section *insn_sec, unsigned long insn_off)
763
+{
764
+ struct symbol *sym = insn_sec->sym;
765
+ int addend = insn_off;
766
+
767
+ if (!sym) {
768
+ /*
769
+ * Due to how weak functions work, we must use section based
770
+ * relocations. Symbol based relocations would result in the
771
+ * weak and non-weak function annotations being overlaid on the
772
+ * non-weak function after linking.
773
+ */
774
+ sym = elf_create_section_symbol(elf, insn_sec);
775
+ if (!sym)
776
+ return -1;
777
+
778
+ insn_sec->sym = sym;
779
+ }
780
+
781
+ return elf_add_reloc(elf, sec, offset, type, sym, addend);
782
+}
783
+
784
+static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
785
+{
786
+ if (!gelf_getrel(sec->data, i, &reloc->rel)) {
787
+ WARN_ELF("gelf_getrel");
788
+ return -1;
789
+ }
790
+ reloc->type = GELF_R_TYPE(reloc->rel.r_info);
791
+ reloc->addend = 0;
792
+ reloc->offset = reloc->rel.r_offset;
793
+ *symndx = GELF_R_SYM(reloc->rel.r_info);
794
+ return 0;
795
+}
796
+
797
+static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
798
+{
799
+ if (!gelf_getrela(sec->data, i, &reloc->rela)) {
800
+ WARN_ELF("gelf_getrela");
801
+ return -1;
802
+ }
803
+ reloc->type = GELF_R_TYPE(reloc->rela.r_info);
804
+ reloc->addend = reloc->rela.r_addend;
805
+ reloc->offset = reloc->rela.r_offset;
806
+ *symndx = GELF_R_SYM(reloc->rela.r_info);
807
+ return 0;
808
+}
809
+
810
+static int read_relocs(struct elf *elf)
811
+{
812
+ struct section *sec;
813
+ struct reloc *reloc;
814
+ int i;
815
+ unsigned int symndx;
816
+ unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
817
+
818
+ list_for_each_entry(sec, &elf->sections, list) {
819
+ if ((sec->sh.sh_type != SHT_RELA) &&
820
+ (sec->sh.sh_type != SHT_REL))
821
+ continue;
822
+
823
+ sec->base = find_section_by_index(elf, sec->sh.sh_info);
824
+ if (!sec->base) {
825
+ WARN("can't find base section for reloc section %s",
826
+ sec->name);
827
+ return -1;
828
+ }
829
+
830
+ sec->base->reloc = sec;
831
+
832
+ nr_reloc = 0;
833
+ for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
834
+ reloc = malloc(sizeof(*reloc));
835
+ if (!reloc) {
836
+ perror("malloc");
837
+ return -1;
838
+ }
839
+ memset(reloc, 0, sizeof(*reloc));
840
+ switch (sec->sh.sh_type) {
841
+ case SHT_REL:
842
+ if (read_rel_reloc(sec, i, reloc, &symndx))
843
+ return -1;
844
+ break;
845
+ case SHT_RELA:
846
+ if (read_rela_reloc(sec, i, reloc, &symndx))
847
+ return -1;
848
+ break;
849
+ default: return -1;
850
+ }
851
+
852
+ reloc->sec = sec;
853
+ reloc->idx = i;
854
+ reloc->sym = find_symbol_by_index(elf, symndx);
855
+ if (!reloc->sym) {
856
+ WARN("can't find reloc entry symbol %d for %s",
857
+ symndx, sec->name);
858
+ return -1;
859
+ }
860
+
861
+ list_add_tail(&reloc->list, &sec->reloc_list);
862
+ elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
863
+
864
+ nr_reloc++;
865
+ }
866
+ max_reloc = max(max_reloc, nr_reloc);
867
+ tot_reloc += nr_reloc;
868
+ }
869
+
870
+ if (stats) {
871
+ printf("max_reloc: %lu\n", max_reloc);
872
+ printf("tot_reloc: %lu\n", tot_reloc);
873
+ }
874
+
875
+ return 0;
876
+}
877
+
878
+struct elf *elf_open_read(const char *name, int flags)
413879 {
414880 struct elf *elf;
415881 Elf_Cmd cmd;
....@@ -421,9 +887,15 @@
421887 perror("malloc");
422888 return NULL;
423889 }
424
- memset(elf, 0, sizeof(*elf));
890
+ memset(elf, 0, offsetof(struct elf, sections));
425891
426892 INIT_LIST_HEAD(&elf->sections);
893
+
894
+ elf_hash_init(elf->symbol_hash);
895
+ elf_hash_init(elf->symbol_name_hash);
896
+ elf_hash_init(elf->section_hash);
897
+ elf_hash_init(elf->section_name_hash);
898
+ elf_hash_init(elf->reloc_hash);
427899
428900 elf->fd = open(name, flags);
429901 if (elf->fd == -1) {
....@@ -456,7 +928,7 @@
456928 if (read_symbols(elf))
457929 goto err;
458930
459
- if (read_relas(elf))
931
+ if (read_relocs(elf))
460932 goto err;
461933
462934 return elf;
....@@ -466,13 +938,49 @@
466938 return NULL;
467939 }
468940
941
+static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
942
+{
943
+ Elf_Data *data;
944
+ Elf_Scn *s;
945
+ int len;
946
+
947
+ if (!strtab)
948
+ strtab = find_section_by_name(elf, ".strtab");
949
+ if (!strtab) {
950
+ WARN("can't find .strtab section");
951
+ return -1;
952
+ }
953
+
954
+ s = elf_getscn(elf->elf, strtab->idx);
955
+ if (!s) {
956
+ WARN_ELF("elf_getscn");
957
+ return -1;
958
+ }
959
+
960
+ data = elf_newdata(s);
961
+ if (!data) {
962
+ WARN_ELF("elf_newdata");
963
+ return -1;
964
+ }
965
+
966
+ data->d_buf = str;
967
+ data->d_size = strlen(str) + 1;
968
+ data->d_align = 1;
969
+ data->d_type = ELF_T_SYM;
970
+
971
+ len = strtab->len;
972
+ strtab->len += data->d_size;
973
+ strtab->changed = true;
974
+
975
+ return len;
976
+}
977
+
469978 struct section *elf_create_section(struct elf *elf, const char *name,
470
- size_t entsize, int nr)
979
+ unsigned int sh_flags, size_t entsize, int nr)
471980 {
472981 struct section *sec, *shstrtab;
473982 size_t size = entsize * nr;
474
- struct Elf_Scn *s;
475
- Elf_Data *data;
983
+ Elf_Scn *s;
476984
477985 sec = malloc(sizeof(*sec));
478986 if (!sec) {
....@@ -482,11 +990,7 @@
482990 memset(sec, 0, sizeof(*sec));
483991
484992 INIT_LIST_HEAD(&sec->symbol_list);
485
- INIT_LIST_HEAD(&sec->rela_list);
486
- hash_init(sec->rela_hash);
487
- hash_init(sec->symbol_hash);
488
-
489
- list_add_tail(&sec->list, &elf->sections);
993
+ INIT_LIST_HEAD(&sec->reloc_list);
490994
491995 s = elf_newscn(elf->elf);
492996 if (!s) {
....@@ -531,8 +1035,7 @@
5311035 sec->sh.sh_entsize = entsize;
5321036 sec->sh.sh_type = SHT_PROGBITS;
5331037 sec->sh.sh_addralign = 1;
534
- sec->sh.sh_flags = SHF_ALLOC;
535
-
1038
+ sec->sh.sh_flags = SHF_ALLOC | sh_flags;
5361039
5371040 /* Add section name to .shstrtab (or .strtab for Clang) */
5381041 shstrtab = find_section_by_name(elf, ".shstrtab");
....@@ -542,50 +1045,68 @@
5421045 WARN("can't find .shstrtab or .strtab section");
5431046 return NULL;
5441047 }
545
-
546
- s = elf_getscn(elf->elf, shstrtab->idx);
547
- if (!s) {
548
- WARN_ELF("elf_getscn");
1048
+ sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
1049
+ if (sec->sh.sh_name == -1)
5491050 return NULL;
550
- }
5511051
552
- data = elf_newdata(s);
553
- if (!data) {
554
- WARN_ELF("elf_newdata");
555
- return NULL;
556
- }
1052
+ list_add_tail(&sec->list, &elf->sections);
1053
+ elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
1054
+ elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
5571055
558
- data->d_buf = sec->name;
559
- data->d_size = strlen(name) + 1;
560
- data->d_align = 1;
561
-
562
- sec->sh.sh_name = shstrtab->len;
563
-
564
- shstrtab->len += strlen(name) + 1;
565
- shstrtab->changed = true;
1056
+ elf->changed = true;
5661057
5671058 return sec;
5681059 }
5691060
570
-struct section *elf_create_rela_section(struct elf *elf, struct section *base)
1061
+static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base)
5711062 {
572
- char *relaname;
1063
+ char *relocname;
5731064 struct section *sec;
5741065
575
- relaname = malloc(strlen(base->name) + strlen(".rela") + 1);
576
- if (!relaname) {
1066
+ relocname = malloc(strlen(base->name) + strlen(".rel") + 1);
1067
+ if (!relocname) {
5771068 perror("malloc");
5781069 return NULL;
5791070 }
580
- strcpy(relaname, ".rela");
581
- strcat(relaname, base->name);
1071
+ strcpy(relocname, ".rel");
1072
+ strcat(relocname, base->name);
5821073
583
- sec = elf_create_section(elf, relaname, sizeof(GElf_Rela), 0);
584
- free(relaname);
1074
+ sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
1075
+ free(relocname);
5851076 if (!sec)
5861077 return NULL;
5871078
588
- base->rela = sec;
1079
+ base->reloc = sec;
1080
+ sec->base = base;
1081
+
1082
+ sec->sh.sh_type = SHT_REL;
1083
+ sec->sh.sh_addralign = 8;
1084
+ sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
1085
+ sec->sh.sh_info = base->idx;
1086
+ sec->sh.sh_flags = SHF_INFO_LINK;
1087
+
1088
+ return sec;
1089
+}
1090
+
1091
+static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base)
1092
+{
1093
+ char *relocname;
1094
+ struct section *sec;
1095
+
1096
+ relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
1097
+ if (!relocname) {
1098
+ perror("malloc");
1099
+ return NULL;
1100
+ }
1101
+ strcpy(relocname, ".rela");
1102
+ strcat(relocname, base->name);
1103
+
1104
+ sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
1105
+ free(relocname);
1106
+ if (!sec)
1107
+ return NULL;
1108
+
1109
+ base->reloc = sec;
5891110 sec->base = base;
5901111
5911112 sec->sh.sh_type = SHT_RELA;
....@@ -597,35 +1118,135 @@
5971118 return sec;
5981119 }
5991120
600
-int elf_rebuild_rela_section(struct section *sec)
1121
+static struct section *elf_create_reloc_section(struct elf *elf,
1122
+ struct section *base,
1123
+ int reltype)
6011124 {
602
- struct rela *rela;
603
- int nr, idx = 0, size;
604
- GElf_Rela *relas;
1125
+ switch (reltype) {
1126
+ case SHT_REL: return elf_create_rel_reloc_section(elf, base);
1127
+ case SHT_RELA: return elf_create_rela_reloc_section(elf, base);
1128
+ default: return NULL;
1129
+ }
1130
+}
6051131
606
- nr = 0;
607
- list_for_each_entry(rela, &sec->rela_list, list)
608
- nr++;
1132
+static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
1133
+{
1134
+ struct reloc *reloc;
1135
+ int idx = 0, size;
1136
+ GElf_Rel *relocs;
6091137
610
- size = nr * sizeof(*relas);
611
- relas = malloc(size);
612
- if (!relas) {
1138
+ /* Allocate a buffer for relocations */
1139
+ size = nr * sizeof(*relocs);
1140
+ relocs = malloc(size);
1141
+ if (!relocs) {
6131142 perror("malloc");
6141143 return -1;
6151144 }
6161145
617
- sec->data->d_buf = relas;
1146
+ sec->data->d_buf = relocs;
6181147 sec->data->d_size = size;
6191148
6201149 sec->sh.sh_size = size;
6211150
6221151 idx = 0;
623
- list_for_each_entry(rela, &sec->rela_list, list) {
624
- relas[idx].r_offset = rela->offset;
625
- relas[idx].r_addend = rela->addend;
626
- relas[idx].r_info = GELF_R_INFO(rela->sym->idx, rela->type);
1152
+ list_for_each_entry(reloc, &sec->reloc_list, list) {
1153
+ relocs[idx].r_offset = reloc->offset;
1154
+ relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
6271155 idx++;
6281156 }
1157
+
1158
+ return 0;
1159
+}
1160
+
1161
+static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
1162
+{
1163
+ struct reloc *reloc;
1164
+ int idx = 0, size;
1165
+ GElf_Rela *relocs;
1166
+
1167
+ /* Allocate a buffer for relocations with addends */
1168
+ size = nr * sizeof(*relocs);
1169
+ relocs = malloc(size);
1170
+ if (!relocs) {
1171
+ perror("malloc");
1172
+ return -1;
1173
+ }
1174
+
1175
+ sec->data->d_buf = relocs;
1176
+ sec->data->d_size = size;
1177
+
1178
+ sec->sh.sh_size = size;
1179
+
1180
+ idx = 0;
1181
+ list_for_each_entry(reloc, &sec->reloc_list, list) {
1182
+ relocs[idx].r_offset = reloc->offset;
1183
+ relocs[idx].r_addend = reloc->addend;
1184
+ relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1185
+ idx++;
1186
+ }
1187
+
1188
+ return 0;
1189
+}
1190
+
1191
+static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
1192
+{
1193
+ struct reloc *reloc;
1194
+ int nr;
1195
+
1196
+ nr = 0;
1197
+ list_for_each_entry(reloc, &sec->reloc_list, list)
1198
+ nr++;
1199
+
1200
+ switch (sec->sh.sh_type) {
1201
+ case SHT_REL: return elf_rebuild_rel_reloc_section(sec, nr);
1202
+ case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr);
1203
+ default: return -1;
1204
+ }
1205
+}
1206
+
1207
+int elf_write_insn(struct elf *elf, struct section *sec,
1208
+ unsigned long offset, unsigned int len,
1209
+ const char *insn)
1210
+{
1211
+ Elf_Data *data = sec->data;
1212
+
1213
+ if (data->d_type != ELF_T_BYTE || data->d_off) {
1214
+ WARN("write to unexpected data for section: %s", sec->name);
1215
+ return -1;
1216
+ }
1217
+
1218
+ memcpy(data->d_buf + offset, insn, len);
1219
+ elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);
1220
+
1221
+ elf->changed = true;
1222
+
1223
+ return 0;
1224
+}
1225
+
1226
+int elf_write_reloc(struct elf *elf, struct reloc *reloc)
1227
+{
1228
+ struct section *sec = reloc->sec;
1229
+
1230
+ if (sec->sh.sh_type == SHT_REL) {
1231
+ reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1232
+ reloc->rel.r_offset = reloc->offset;
1233
+
1234
+ if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) {
1235
+ WARN_ELF("gelf_update_rel");
1236
+ return -1;
1237
+ }
1238
+ } else {
1239
+ reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1240
+ reloc->rela.r_addend = reloc->addend;
1241
+ reloc->rela.r_offset = reloc->offset;
1242
+
1243
+ if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) {
1244
+ WARN_ELF("gelf_update_rela");
1245
+ return -1;
1246
+ }
1247
+ }
1248
+
1249
+ elf->changed = true;
6291250
6301251 return 0;
6311252 }
....@@ -635,9 +1256,15 @@
6351256 struct section *sec;
6361257 Elf_Scn *s;
6371258
638
- /* Update section headers for changed sections: */
1259
+ /* Update changed relocation sections and section headers: */
6391260 list_for_each_entry(sec, &elf->sections, list) {
6401261 if (sec->changed) {
1262
+ if (sec->base &&
1263
+ elf_rebuild_reloc_section(elf, sec)) {
1264
+ WARN("elf_rebuild_reloc_section");
1265
+ return -1;
1266
+ }
1267
+
6411268 s = elf_getscn(elf->elf, sec->idx);
6421269 if (!s) {
6431270 WARN_ELF("elf_getscn");
....@@ -647,6 +1274,9 @@
6471274 WARN_ELF("gelf_update_shdr");
6481275 return -1;
6491276 }
1277
+
1278
+ sec->changed = false;
1279
+ elf->changed = true;
6501280 }
6511281 }
6521282
....@@ -659,6 +1289,8 @@
6591289 return -1;
6601290 }
6611291
1292
+ elf->changed = false;
1293
+
6621294 return 0;
6631295 }
6641296
....@@ -666,7 +1298,7 @@
6661298 {
6671299 struct section *sec, *tmpsec;
6681300 struct symbol *sym, *tmpsym;
669
- struct rela *rela, *tmprela;
1301
+ struct reloc *reloc, *tmpreloc;
6701302
6711303 if (elf->elf)
6721304 elf_end(elf->elf);
....@@ -680,10 +1312,10 @@
6801312 hash_del(&sym->hash);
6811313 free(sym);
6821314 }
683
- list_for_each_entry_safe(rela, tmprela, &sec->rela_list, list) {
684
- list_del(&rela->list);
685
- hash_del(&rela->hash);
686
- free(rela);
1315
+ list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
1316
+ list_del(&reloc->list);
1317
+ hash_del(&reloc->hash);
1318
+ free(reloc);
6871319 }
6881320 list_del(&sec->list);
6891321 free(sec);