Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/elftoolchain/elfcopy/symbols.c
39481 views
1
/*-
2
* Copyright (c) 2007-2013 Kai Wang
3
* All rights reserved.
4
*
5
* Redistribution and use in source and binary forms, with or without
6
* modification, are permitted provided that the following conditions
7
* are met:
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
*
14
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
* SUCH DAMAGE.
25
*/
26
27
#include <sys/param.h>
28
#include <assert.h>
29
#include <err.h>
30
#include <fnmatch.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
35
#include "elfcopy.h"
36
37
ELFTC_VCSID("$Id: symbols.c 3520 2017-04-17 01:47:52Z kaiwang27 $");
38
39
/* Backwards compatibility for systems with older ELF definitions. */
40
#ifndef STB_GNU_UNIQUE
41
#define STB_GNU_UNIQUE 10
42
#endif
43
44
45
/* Symbol table buffer structure. */
46
struct symbuf {
47
Elf32_Sym *l32; /* 32bit local symbol */
48
Elf32_Sym *g32; /* 32bit global symbol */
49
Elf64_Sym *l64; /* 64bit local symbol */
50
Elf64_Sym *g64; /* 64bit global symbol */
51
size_t ngs, nls; /* number of each kind */
52
size_t gcap, lcap; /* buffer capacities. */
53
};
54
55
struct sthash {
56
LIST_ENTRY(sthash) sh_next;
57
size_t sh_off;
58
};
59
typedef LIST_HEAD(,sthash) hash_head;
60
#define STHASHSIZE 65536
61
62
struct strimpl {
63
char *buf; /* string table */
64
size_t sz; /* entries */
65
size_t cap; /* buffer capacity */
66
hash_head hash[STHASHSIZE];
67
};
68
69
70
/* String table buffer structure. */
71
struct strbuf {
72
struct strimpl l; /* local symbols */
73
struct strimpl g; /* global symbols */
74
};
75
76
static int is_debug_symbol(unsigned char st_info);
77
static int is_global_symbol(unsigned char st_info);
78
static int is_local_symbol(unsigned char st_info);
79
static int is_local_label(const char *name);
80
static int is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s);
81
static int is_remove_symbol(struct elfcopy *ecp, size_t sc, int i,
82
GElf_Sym *s, const char *name);
83
static int is_weak_symbol(unsigned char st_info);
84
static int lookup_exact_string(hash_head *hash, const char *buf,
85
const char *s);
86
static int generate_symbols(struct elfcopy *ecp);
87
static void mark_reloc_symbols(struct elfcopy *ecp, size_t sc);
88
static void mark_section_group_symbols(struct elfcopy *ecp, size_t sc);
89
uint32_t str_hash(const char *s);
90
91
/* Convenient bit vector operation macros. */
92
#define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7))
93
#define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7)))
94
#define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7)))
95
96
static int
97
is_debug_symbol(unsigned char st_info)
98
{
99
100
if (GELF_ST_TYPE(st_info) == STT_SECTION ||
101
GELF_ST_TYPE(st_info) == STT_FILE)
102
return (1);
103
104
return (0);
105
}
106
107
static int
108
is_global_symbol(unsigned char st_info)
109
{
110
111
if (GELF_ST_BIND(st_info) == STB_GLOBAL ||
112
GELF_ST_BIND(st_info) == STB_GNU_UNIQUE)
113
return (1);
114
115
return (0);
116
}
117
118
static int
119
is_weak_symbol(unsigned char st_info)
120
{
121
122
if (GELF_ST_BIND(st_info) == STB_WEAK)
123
return (1);
124
125
return (0);
126
}
127
128
static int
129
is_local_symbol(unsigned char st_info)
130
{
131
132
if (GELF_ST_BIND(st_info) == STB_LOCAL)
133
return (1);
134
135
return (0);
136
}
137
138
static int
139
is_hidden_symbol(unsigned char st_other)
140
{
141
142
if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN ||
143
GELF_ST_VISIBILITY(st_other) == STV_INTERNAL)
144
return (1);
145
146
return (0);
147
}
148
149
static int
150
is_local_label(const char *name)
151
{
152
153
/* Compiler generated local symbols that start with .L */
154
if (name[0] == '.' && name[1] == 'L')
155
return (1);
156
157
return (0);
158
}
159
160
/*
161
* Symbols related to relocation are needed.
162
*/
163
static int
164
is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s)
165
{
166
167
/* If symbol involves relocation, it is needed. */
168
if (BIT_ISSET(ecp->v_rel, i))
169
return (1);
170
171
/* Symbols referred by COMDAT sections are needed. */
172
if (BIT_ISSET(ecp->v_grp, i))
173
return (1);
174
175
/*
176
* For relocatable files (.o files), global and weak symbols
177
* are needed.
178
*/
179
if (ecp->flags & RELOCATABLE) {
180
if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info))
181
return (1);
182
}
183
184
return (0);
185
}
186
187
static int
188
is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s,
189
const char *name)
190
{
191
GElf_Sym sym0 = {
192
0, /* st_name */
193
0, /* st_value */
194
0, /* st_size */
195
0, /* st_info */
196
0, /* st_other */
197
SHN_UNDEF, /* st_shndx */
198
};
199
200
/*
201
* Keep the first symbol if it is the special reserved symbol.
202
* XXX Should we generate one if it's missing?
203
*/
204
if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym)))
205
return (0);
206
207
/* Remove the symbol if the section it refers to was removed. */
208
if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE &&
209
ecp->secndx[s->st_shndx] == 0)
210
return (1);
211
212
/* Keep the symbol if specified by command line option -K. */
213
if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL)
214
return (0);
215
216
if (ecp->strip == STRIP_ALL)
217
return (1);
218
219
/* Mark symbols used in relocation. */
220
if (ecp->v_rel == NULL)
221
mark_reloc_symbols(ecp, sc);
222
223
/* Mark symbols used in section groups. */
224
if (ecp->v_grp == NULL)
225
mark_section_group_symbols(ecp, sc);
226
227
/*
228
* Strip the symbol if specified by command line option -N,
229
* unless it's used in relocation.
230
*/
231
if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL) {
232
if (BIT_ISSET(ecp->v_rel, i)) {
233
warnx("not stripping symbol `%s' because it is named"
234
" in a relocation", name);
235
return (0);
236
}
237
return (1);
238
}
239
240
if (is_needed_symbol(ecp, i, s))
241
return (0);
242
243
if (ecp->strip == STRIP_UNNEEDED)
244
return (1);
245
246
if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) &&
247
!is_debug_symbol(s->st_info))
248
return (1);
249
250
if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) &&
251
!is_debug_symbol(s->st_info) && is_local_label(name))
252
return (1);
253
254
if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info))
255
return (1);
256
257
return (0);
258
}
259
260
/*
261
* Mark symbols referred by relocation entries.
262
*/
263
static void
264
mark_reloc_symbols(struct elfcopy *ecp, size_t sc)
265
{
266
const char *name;
267
Elf_Data *d;
268
Elf_Scn *s;
269
GElf_Rel r;
270
GElf_Rela ra;
271
GElf_Shdr sh;
272
size_t n, indx;
273
int elferr, i, len;
274
275
ecp->v_rel = calloc((sc + 7) / 8, 1);
276
if (ecp->v_rel == NULL)
277
err(EXIT_FAILURE, "calloc failed");
278
279
if (elf_getshstrndx(ecp->ein, &indx) == 0)
280
errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
281
elf_errmsg(-1));
282
283
s = NULL;
284
while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
285
if (gelf_getshdr(s, &sh) != &sh)
286
errx(EXIT_FAILURE, "elf_getshdr failed: %s",
287
elf_errmsg(-1));
288
289
if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA)
290
continue;
291
292
/*
293
* Skip if this reloc section won't appear in the
294
* output object.
295
*/
296
if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
297
errx(EXIT_FAILURE, "elf_strptr failed: %s",
298
elf_errmsg(-1));
299
if (is_remove_section(ecp, name) ||
300
is_remove_reloc_sec(ecp, sh.sh_info))
301
continue;
302
303
/* Skip if it's not for .symtab */
304
if (sh.sh_link != elf_ndxscn(ecp->symtab->is))
305
continue;
306
307
d = NULL;
308
n = 0;
309
while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) {
310
len = d->d_size / sh.sh_entsize;
311
for (i = 0; i < len; i++) {
312
if (sh.sh_type == SHT_REL) {
313
if (gelf_getrel(d, i, &r) != &r)
314
errx(EXIT_FAILURE,
315
"elf_getrel failed: %s",
316
elf_errmsg(-1));
317
n = GELF_R_SYM(r.r_info);
318
} else {
319
if (gelf_getrela(d, i, &ra) != &ra)
320
errx(EXIT_FAILURE,
321
"elf_getrela failed: %s",
322
elf_errmsg(-1));
323
n = GELF_R_SYM(ra.r_info);
324
}
325
if (n > 0 && n < sc)
326
BIT_SET(ecp->v_rel, n);
327
else if (n != 0)
328
warnx("invalid symbox index");
329
}
330
}
331
elferr = elf_errno();
332
if (elferr != 0)
333
errx(EXIT_FAILURE, "elf_getdata failed: %s",
334
elf_errmsg(elferr));
335
}
336
elferr = elf_errno();
337
if (elferr != 0)
338
errx(EXIT_FAILURE, "elf_nextscn failed: %s",
339
elf_errmsg(elferr));
340
}
341
342
static void
343
mark_section_group_symbols(struct elfcopy *ecp, size_t sc)
344
{
345
const char *name;
346
Elf_Scn *s;
347
GElf_Shdr sh;
348
size_t indx;
349
int elferr;
350
351
ecp->v_grp = calloc((sc + 7) / 8, 1);
352
if (ecp->v_grp == NULL)
353
err(EXIT_FAILURE, "calloc failed");
354
355
if (elf_getshstrndx(ecp->ein, &indx) == 0)
356
errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
357
elf_errmsg(-1));
358
359
s = NULL;
360
while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
361
if (gelf_getshdr(s, &sh) != &sh)
362
errx(EXIT_FAILURE, "elf_getshdr failed: %s",
363
elf_errmsg(-1));
364
365
if (sh.sh_type != SHT_GROUP)
366
continue;
367
368
if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
369
errx(EXIT_FAILURE, "elf_strptr failed: %s",
370
elf_errmsg(-1));
371
if (is_remove_section(ecp, name))
372
continue;
373
374
if (sh.sh_info > 0 && sh.sh_info < sc)
375
BIT_SET(ecp->v_grp, sh.sh_info);
376
else if (sh.sh_info != 0)
377
warnx("invalid symbox index");
378
}
379
elferr = elf_errno();
380
if (elferr != 0)
381
errx(EXIT_FAILURE, "elf_nextscn failed: %s",
382
elf_errmsg(elferr));
383
}
384
385
static int
386
generate_symbols(struct elfcopy *ecp)
387
{
388
struct section *s;
389
struct symop *sp;
390
struct symbuf *sy_buf;
391
struct strbuf *st_buf;
392
const char *name;
393
char *newname;
394
unsigned char *gsym;
395
GElf_Shdr ish;
396
GElf_Sym sym;
397
Elf_Data* id;
398
Elf_Scn *is;
399
size_t ishstrndx, namelen, ndx, sc, symndx;
400
int ec, elferr, i;
401
402
if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0)
403
errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
404
elf_errmsg(-1));
405
if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE)
406
errx(EXIT_FAILURE, "gelf_getclass failed: %s",
407
elf_errmsg(-1));
408
409
/* Create buffers for .symtab and .strtab. */
410
if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
411
err(EXIT_FAILURE, "calloc failed");
412
if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
413
err(EXIT_FAILURE, "calloc failed");
414
sy_buf->gcap = sy_buf->lcap = 64;
415
st_buf->g.cap = 256;
416
st_buf->l.cap = 64;
417
st_buf->l.sz = 1; /* '\0' at start. */
418
st_buf->g.sz = 0;
419
420
ecp->symtab->sz = 0;
421
ecp->strtab->sz = 0;
422
ecp->symtab->buf = sy_buf;
423
ecp->strtab->buf = st_buf;
424
425
gsym = NULL;
426
427
/*
428
* Create bit vector v_secsym, which is used to mark sections
429
* that already have corresponding STT_SECTION symbols.
430
*/
431
ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1);
432
if (ecp->v_secsym == NULL)
433
err(EXIT_FAILURE, "calloc failed");
434
435
/* Locate .strtab of input object. */
436
symndx = 0;
437
name = NULL;
438
is = NULL;
439
while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
440
if (gelf_getshdr(is, &ish) != &ish)
441
errx(EXIT_FAILURE, "elf_getshdr failed: %s",
442
elf_errmsg(-1));
443
if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
444
NULL)
445
errx(EXIT_FAILURE, "elf_strptr failed: %s",
446
elf_errmsg(-1));
447
if (strcmp(name, ".strtab") == 0) {
448
symndx = elf_ndxscn(is);
449
break;
450
}
451
}
452
elferr = elf_errno();
453
if (elferr != 0)
454
errx(EXIT_FAILURE, "elf_nextscn failed: %s",
455
elf_errmsg(elferr));
456
457
/* Symbol table should exist if this function is called. */
458
if (symndx == 0) {
459
warnx("can't find .strtab section");
460
goto clean;
461
}
462
463
/* Locate .symtab of input object. */
464
is = NULL;
465
while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
466
if (gelf_getshdr(is, &ish) != &ish)
467
errx(EXIT_FAILURE, "elf_getshdr failed: %s",
468
elf_errmsg(-1));
469
if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
470
NULL)
471
errx(EXIT_FAILURE, "elf_strptr failed: %s",
472
elf_errmsg(-1));
473
if (strcmp(name, ".symtab") == 0)
474
break;
475
}
476
elferr = elf_errno();
477
if (elferr != 0)
478
errx(EXIT_FAILURE, "elf_nextscn failed: %s",
479
elf_errmsg(elferr));
480
if (is == NULL)
481
errx(EXIT_FAILURE, "can't find .strtab section");
482
483
/*
484
* Create bit vector gsym to mark global symbols, and symndx
485
* to keep track of symbol index changes from input object to
486
* output object, it is used by update_reloc() later to update
487
* relocation information.
488
*/
489
sc = ish.sh_size / ish.sh_entsize;
490
if (sc > 0) {
491
ecp->symndx = calloc(sc, sizeof(*ecp->symndx));
492
if (ecp->symndx == NULL)
493
err(EXIT_FAILURE, "calloc failed");
494
gsym = calloc((sc + 7) / 8, sizeof(*gsym));
495
if (gsym == NULL)
496
err(EXIT_FAILURE, "calloc failed");
497
if ((id = elf_getdata(is, NULL)) == NULL) {
498
elferr = elf_errno();
499
if (elferr != 0)
500
errx(EXIT_FAILURE, "elf_getdata failed: %s",
501
elf_errmsg(elferr));
502
goto clean;
503
}
504
} else
505
return (0);
506
507
/* Copy/Filter each symbol. */
508
for (i = 0; (size_t)i < sc; i++) {
509
if (gelf_getsym(id, i, &sym) != &sym)
510
errx(EXIT_FAILURE, "gelf_getsym failed: %s",
511
elf_errmsg(-1));
512
if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL)
513
errx(EXIT_FAILURE, "elf_strptr failed: %s",
514
elf_errmsg(-1));
515
516
/* Symbol filtering. */
517
if (is_remove_symbol(ecp, sc, i, &sym, name) != 0)
518
continue;
519
520
/* Check if we need to change the binding of this symbol. */
521
if (is_global_symbol(sym.st_info) ||
522
is_weak_symbol(sym.st_info)) {
523
/*
524
* XXX Binutils objcopy does not weaken certain
525
* symbols.
526
*/
527
if (ecp->flags & WEAKEN_ALL ||
528
lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL)
529
sym.st_info = GELF_ST_INFO(STB_WEAK,
530
GELF_ST_TYPE(sym.st_info));
531
/* Do not localize undefined symbols. */
532
if (sym.st_shndx != SHN_UNDEF &&
533
lookup_symop_list(ecp, name, SYMOP_LOCALIZE) !=
534
NULL)
535
sym.st_info = GELF_ST_INFO(STB_LOCAL,
536
GELF_ST_TYPE(sym.st_info));
537
if (ecp->flags & KEEP_GLOBAL &&
538
sym.st_shndx != SHN_UNDEF &&
539
lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL)
540
sym.st_info = GELF_ST_INFO(STB_LOCAL,
541
GELF_ST_TYPE(sym.st_info));
542
if (ecp->flags & LOCALIZE_HIDDEN &&
543
sym.st_shndx != SHN_UNDEF &&
544
is_hidden_symbol(sym.st_other))
545
sym.st_info = GELF_ST_INFO(STB_LOCAL,
546
GELF_ST_TYPE(sym.st_info));
547
} else {
548
/* STB_LOCAL binding. */
549
if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) !=
550
NULL)
551
sym.st_info = GELF_ST_INFO(STB_GLOBAL,
552
GELF_ST_TYPE(sym.st_info));
553
/* XXX We should globalize weak symbol? */
554
}
555
556
/* Check if we need to rename this symbol. */
557
if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL)
558
name = sp->newname;
559
560
/* Check if we need to prefix the symbols. */
561
newname = NULL;
562
if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') {
563
namelen = strlen(name) + strlen(ecp->prefix_sym) + 1;
564
if ((newname = malloc(namelen)) == NULL)
565
err(EXIT_FAILURE, "malloc failed");
566
snprintf(newname, namelen, "%s%s", ecp->prefix_sym,
567
name);
568
name = newname;
569
}
570
571
/* Copy symbol, mark global/weak symbol and add to index map. */
572
if (is_global_symbol(sym.st_info) ||
573
is_weak_symbol(sym.st_info)) {
574
BIT_SET(gsym, i);
575
ecp->symndx[i] = sy_buf->ngs;
576
} else
577
ecp->symndx[i] = sy_buf->nls;
578
add_to_symtab(ecp, name, sym.st_value, sym.st_size,
579
sym.st_shndx, sym.st_info, sym.st_other, 0);
580
581
if (newname != NULL)
582
free(newname);
583
584
/*
585
* If the symbol is a STT_SECTION symbol, mark the section
586
* it points to.
587
*/
588
if (GELF_ST_TYPE(sym.st_info) == STT_SECTION &&
589
sym.st_shndx < SHN_LORESERVE) {
590
assert(ecp->secndx[sym.st_shndx] < (uint64_t)ecp->nos);
591
BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]);
592
}
593
}
594
595
/*
596
* Give up if there is no real symbols inside the table.
597
* XXX The logic here needs to be improved. We need to
598
* check if that only local symbol is the reserved symbol.
599
*/
600
if (sy_buf->nls <= 1 && sy_buf->ngs == 0)
601
goto clean;
602
603
/*
604
* Create STT_SECTION symbols for sections that do not already
605
* got one. However, we do not create STT_SECTION symbol for
606
* .symtab, .strtab, .shstrtab and reloc sec of relocatables.
607
*/
608
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
609
if (s->pseudo)
610
continue;
611
if (strcmp(s->name, ".symtab") == 0 ||
612
strcmp(s->name, ".strtab") == 0 ||
613
strcmp(s->name, ".shstrtab") == 0)
614
continue;
615
if ((ecp->flags & RELOCATABLE) != 0 &&
616
((s->type == SHT_REL) || (s->type == SHT_RELA)))
617
continue;
618
619
if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
620
errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
621
elf_errmsg(-1));
622
623
if (!BIT_ISSET(ecp->v_secsym, ndx)) {
624
sym.st_name = 0;
625
sym.st_value = s->vma;
626
sym.st_size = 0;
627
sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
628
sym.st_other = STV_DEFAULT;
629
/*
630
* Don't let add_to_symtab() touch sym.st_shndx.
631
* In this case, we know the index already.
632
*/
633
add_to_symtab(ecp, NULL, sym.st_value, sym.st_size,
634
ndx, sym.st_info, sym.st_other, 1);
635
}
636
}
637
638
/*
639
* Update st_name and index map for global/weak symbols. Note that
640
* global/weak symbols are put after local symbols.
641
*/
642
if (gsym != NULL) {
643
for(i = 0; (size_t) i < sc; i++) {
644
if (!BIT_ISSET(gsym, i))
645
continue;
646
647
/* Update st_name. */
648
if (ec == ELFCLASS32)
649
sy_buf->g32[ecp->symndx[i]].st_name +=
650
st_buf->l.sz;
651
else
652
sy_buf->g64[ecp->symndx[i]].st_name +=
653
st_buf->l.sz;
654
655
/* Update index map. */
656
ecp->symndx[i] += sy_buf->nls;
657
}
658
free(gsym);
659
}
660
661
return (1);
662
663
clean:
664
free(gsym);
665
free_symtab(ecp);
666
667
return (0);
668
}
669
670
void
671
create_symtab(struct elfcopy *ecp)
672
{
673
struct section *s, *sy, *st;
674
size_t maxndx, ndx;
675
676
sy = ecp->symtab;
677
st = ecp->strtab;
678
679
assert(sy != NULL && st != NULL);
680
681
/*
682
* Set section index map for .symtab and .strtab. We need to set
683
* these map because otherwise symbols which refer to .symtab and
684
* .strtab will be removed by symbol filtering unconditionally.
685
* And we have to figure out scn index this way (instead of calling
686
* elf_ndxscn) because we can not create Elf_Scn before we're certain
687
* that .symtab and .strtab will exist in the output object.
688
*/
689
maxndx = 0;
690
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
691
if (s->os == NULL)
692
continue;
693
if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
694
errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
695
elf_errmsg(-1));
696
if (ndx > maxndx)
697
maxndx = ndx;
698
}
699
ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
700
ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
701
702
/*
703
* Generate symbols for output object if SYMTAB_INTACT is not set.
704
* If there is no symbol in the input object or all the symbols are
705
* stripped, then free all the resouces allotted for symbol table,
706
* and clear SYMTAB_EXIST flag.
707
*/
708
if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) {
709
TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list);
710
TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list);
711
free(ecp->symtab->buf);
712
free(ecp->symtab);
713
free(ecp->strtab->buf);
714
free(ecp->strtab);
715
ecp->symtab = NULL;
716
ecp->strtab = NULL;
717
ecp->flags &= ~SYMTAB_EXIST;
718
return;
719
}
720
721
/* Create output Elf_Scn for .symtab and .strtab. */
722
if ((sy->os = elf_newscn(ecp->eout)) == NULL ||
723
(st->os = elf_newscn(ecp->eout)) == NULL)
724
errx(EXIT_FAILURE, "elf_newscn failed: %s",
725
elf_errmsg(-1));
726
/* Update secndx anyway. */
727
ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os);
728
ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os);
729
730
/*
731
* Copy .symtab and .strtab section headers from input to output
732
* object to start with, these will be overridden later if need.
733
*/
734
copy_shdr(ecp, sy, ".symtab", 1, 0);
735
copy_shdr(ecp, st, ".strtab", 1, 0);
736
737
/* Copy verbatim if symbol table is intact. */
738
if (ecp->flags & SYMTAB_INTACT) {
739
copy_data(sy);
740
copy_data(st);
741
return;
742
}
743
744
create_symtab_data(ecp);
745
}
746
747
void
748
free_symtab(struct elfcopy *ecp)
749
{
750
struct symbuf *sy_buf;
751
struct strbuf *st_buf;
752
struct sthash *sh, *shtmp;
753
int i;
754
755
if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
756
sy_buf = ecp->symtab->buf;
757
if (sy_buf->l32 != NULL)
758
free(sy_buf->l32);
759
if (sy_buf->g32 != NULL)
760
free(sy_buf->g32);
761
if (sy_buf->l64 != NULL)
762
free(sy_buf->l64);
763
if (sy_buf->g64 != NULL)
764
free(sy_buf->g64);
765
}
766
767
if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
768
st_buf = ecp->strtab->buf;
769
if (st_buf->l.buf != NULL)
770
free(st_buf->l.buf);
771
if (st_buf->g.buf != NULL)
772
free(st_buf->g.buf);
773
for (i = 0; i < STHASHSIZE; i++) {
774
LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next,
775
shtmp) {
776
LIST_REMOVE(sh, sh_next);
777
free(sh);
778
}
779
LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next,
780
shtmp) {
781
LIST_REMOVE(sh, sh_next);
782
free(sh);
783
}
784
}
785
}
786
787
if (ecp->symndx != NULL) {
788
free(ecp->symndx);
789
ecp->symndx = NULL;
790
}
791
if (ecp->v_rel != NULL) {
792
free(ecp->v_rel);
793
ecp->v_rel = NULL;
794
}
795
if (ecp->v_grp != NULL) {
796
free(ecp->v_grp);
797
ecp->v_grp = NULL;
798
}
799
if (ecp->v_secsym != NULL) {
800
free(ecp->v_secsym);
801
ecp->v_secsym = NULL;
802
}
803
}
804
805
void
806
create_external_symtab(struct elfcopy *ecp)
807
{
808
struct section *s;
809
struct symbuf *sy_buf;
810
struct strbuf *st_buf;
811
GElf_Shdr sh;
812
size_t ndx;
813
814
if (ecp->oec == ELFCLASS32)
815
ecp->symtab = create_external_section(ecp, ".symtab", NULL,
816
NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0);
817
else
818
ecp->symtab = create_external_section(ecp, ".symtab", NULL,
819
NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
820
821
ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
822
SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
823
824
/* Let sh_link field of .symtab section point to .strtab section. */
825
if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
826
errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
827
elf_errmsg(-1));
828
sh.sh_link = elf_ndxscn(ecp->strtab->os);
829
if (!gelf_update_shdr(ecp->symtab->os, &sh))
830
errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
831
elf_errmsg(-1));
832
833
/* Create buffers for .symtab and .strtab. */
834
if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
835
err(EXIT_FAILURE, "calloc failed");
836
if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
837
err(EXIT_FAILURE, "calloc failed");
838
sy_buf->gcap = sy_buf->lcap = 64;
839
st_buf->g.cap = 256;
840
st_buf->l.cap = 64;
841
st_buf->l.sz = 1; /* '\0' at start. */
842
st_buf->g.sz = 0;
843
844
ecp->symtab->sz = 0;
845
ecp->strtab->sz = 0;
846
ecp->symtab->buf = sy_buf;
847
ecp->strtab->buf = st_buf;
848
849
/* Always create the special symbol at the symtab beginning. */
850
add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF,
851
ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1);
852
853
/* Create STT_SECTION symbols. */
854
TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
855
if (s->pseudo)
856
continue;
857
if (strcmp(s->name, ".symtab") == 0 ||
858
strcmp(s->name, ".strtab") == 0 ||
859
strcmp(s->name, ".shstrtab") == 0)
860
continue;
861
(void) elf_errno();
862
if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
863
warnx("elf_ndxscn failed: %s",
864
elf_errmsg(-1));
865
continue;
866
}
867
add_to_symtab(ecp, NULL, 0, 0, ndx,
868
GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
869
}
870
}
871
872
void
873
add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value,
874
uint64_t st_size, uint16_t st_shndx, unsigned char st_info,
875
unsigned char st_other, int ndx_known)
876
{
877
struct symbuf *sy_buf;
878
struct strbuf *st_buf;
879
struct sthash *sh;
880
uint32_t hash;
881
int pos;
882
883
/*
884
* Convenient macro for copying global/local 32/64 bit symbols
885
* from input object to the buffer created for output object.
886
* It handles buffer growing, st_name calculating and st_shndx
887
* updating for symbols with non-special section index.
888
*/
889
#define _ST_NAME_EMPTY_l 0
890
#define _ST_NAME_EMPTY_g -1
891
#define _ADDSYM(B, SZ) do { \
892
if (sy_buf->B##SZ == NULL) { \
893
sy_buf->B##SZ = malloc(sy_buf->B##cap * \
894
sizeof(Elf##SZ##_Sym)); \
895
if (sy_buf->B##SZ == NULL) \
896
err(EXIT_FAILURE, "malloc failed"); \
897
} else if (sy_buf->n##B##s >= sy_buf->B##cap) { \
898
sy_buf->B##cap *= 2; \
899
sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap * \
900
sizeof(Elf##SZ##_Sym)); \
901
if (sy_buf->B##SZ == NULL) \
902
err(EXIT_FAILURE, "realloc failed"); \
903
} \
904
sy_buf->B##SZ[sy_buf->n##B##s].st_info = st_info; \
905
sy_buf->B##SZ[sy_buf->n##B##s].st_other = st_other; \
906
sy_buf->B##SZ[sy_buf->n##B##s].st_value = st_value; \
907
sy_buf->B##SZ[sy_buf->n##B##s].st_size = st_size; \
908
if (ndx_known) \
909
sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \
910
else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE) \
911
sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx; \
912
else \
913
sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = \
914
ecp->secndx[st_shndx]; \
915
if (st_buf->B.buf == NULL) { \
916
st_buf->B.buf = calloc(st_buf->B.cap, \
917
sizeof(*st_buf->B.buf)); \
918
if (st_buf->B.buf == NULL) \
919
err(EXIT_FAILURE, "malloc failed"); \
920
} \
921
if (name != NULL && *name != '\0') { \
922
pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\
923
name); \
924
if (pos != -1) \
925
sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos; \
926
else { \
927
sy_buf->B##SZ[sy_buf->n##B##s].st_name = \
928
st_buf->B.sz; \
929
while (st_buf->B.sz + strlen(name) >= \
930
st_buf->B.cap - 1) { \
931
st_buf->B.cap *= 2; \
932
st_buf->B.buf = realloc(st_buf->B.buf, \
933
st_buf->B.cap); \
934
if (st_buf->B.buf == NULL) \
935
err(EXIT_FAILURE, \
936
"realloc failed"); \
937
} \
938
if ((sh = malloc(sizeof(*sh))) == NULL) \
939
err(EXIT_FAILURE, "malloc failed"); \
940
sh->sh_off = st_buf->B.sz; \
941
hash = str_hash(name); \
942
LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh, \
943
sh_next); \
944
strncpy(&st_buf->B.buf[st_buf->B.sz], name, \
945
strlen(name)); \
946
st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \
947
st_buf->B.sz += strlen(name) + 1; \
948
} \
949
} else \
950
sy_buf->B##SZ[sy_buf->n##B##s].st_name = \
951
(Elf##SZ##_Word)_ST_NAME_EMPTY_##B; \
952
sy_buf->n##B##s++; \
953
} while (0)
954
955
sy_buf = ecp->symtab->buf;
956
st_buf = ecp->strtab->buf;
957
958
if (ecp->oec == ELFCLASS32) {
959
if (is_local_symbol(st_info))
960
_ADDSYM(l, 32);
961
else
962
_ADDSYM(g, 32);
963
} else {
964
if (is_local_symbol(st_info))
965
_ADDSYM(l, 64);
966
else
967
_ADDSYM(g, 64);
968
}
969
970
/* Update section size. */
971
ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) *
972
(ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym));
973
ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz;
974
975
#undef _ADDSYM
976
#undef _ST_NAME_EMPTY_l
977
#undef _ST_NAME_EMPTY_g
978
}
979
980
void
981
finalize_external_symtab(struct elfcopy *ecp)
982
{
983
struct symbuf *sy_buf;
984
struct strbuf *st_buf;
985
int i;
986
987
/*
988
* Update st_name for global/weak symbols. (global/weak symbols
989
* are put after local symbols)
990
*/
991
sy_buf = ecp->symtab->buf;
992
st_buf = ecp->strtab->buf;
993
for (i = 0; (size_t) i < sy_buf->ngs; i++) {
994
if (ecp->oec == ELFCLASS32) {
995
if (sy_buf->g32[i].st_name == (Elf32_Word)-1)
996
sy_buf->g32[i].st_name = 0;
997
else
998
sy_buf->g32[i].st_name += st_buf->l.sz;
999
} else {
1000
if (sy_buf->g64[i].st_name == (Elf64_Word)-1)
1001
sy_buf->g64[i].st_name = 0;
1002
else
1003
sy_buf->g64[i].st_name += st_buf->l.sz;
1004
}
1005
}
1006
}
1007
1008
void
1009
create_symtab_data(struct elfcopy *ecp)
1010
{
1011
struct section *sy, *st;
1012
struct symbuf *sy_buf;
1013
struct strbuf *st_buf;
1014
Elf_Data *gsydata, *lsydata, *gstdata, *lstdata;
1015
GElf_Shdr shy, sht;
1016
1017
sy = ecp->symtab;
1018
st = ecp->strtab;
1019
1020
if (gelf_getshdr(sy->os, &shy) == NULL)
1021
errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1022
elf_errmsg(-1));
1023
if (gelf_getshdr(st->os, &sht) == NULL)
1024
errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1025
elf_errmsg(-1));
1026
1027
/*
1028
* Create two Elf_Data for .symtab section of output object, one
1029
* for local symbols and another for global symbols. Note that
1030
* local symbols appear first in the .symtab.
1031
*/
1032
sy_buf = sy->buf;
1033
if (sy_buf->nls > 0) {
1034
if ((lsydata = elf_newdata(sy->os)) == NULL)
1035
errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1036
elf_errmsg(-1));
1037
if (ecp->oec == ELFCLASS32) {
1038
lsydata->d_align = 4;
1039
lsydata->d_off = 0;
1040
lsydata->d_buf = sy_buf->l32;
1041
lsydata->d_size = sy_buf->nls *
1042
sizeof(Elf32_Sym);
1043
lsydata->d_type = ELF_T_SYM;
1044
lsydata->d_version = EV_CURRENT;
1045
} else {
1046
lsydata->d_align = 8;
1047
lsydata->d_off = 0;
1048
lsydata->d_buf = sy_buf->l64;
1049
lsydata->d_size = sy_buf->nls *
1050
sizeof(Elf64_Sym);
1051
lsydata->d_type = ELF_T_SYM;
1052
lsydata->d_version = EV_CURRENT;
1053
}
1054
}
1055
if (sy_buf->ngs > 0) {
1056
if ((gsydata = elf_newdata(sy->os)) == NULL)
1057
errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1058
elf_errmsg(-1));
1059
if (ecp->oec == ELFCLASS32) {
1060
gsydata->d_align = 4;
1061
gsydata->d_off = sy_buf->nls *
1062
sizeof(Elf32_Sym);
1063
gsydata->d_buf = sy_buf->g32;
1064
gsydata->d_size = sy_buf->ngs *
1065
sizeof(Elf32_Sym);
1066
gsydata->d_type = ELF_T_SYM;
1067
gsydata->d_version = EV_CURRENT;
1068
} else {
1069
gsydata->d_align = 8;
1070
gsydata->d_off = sy_buf->nls *
1071
sizeof(Elf64_Sym);
1072
gsydata->d_buf = sy_buf->g64;
1073
gsydata->d_size = sy_buf->ngs *
1074
sizeof(Elf64_Sym);
1075
gsydata->d_type = ELF_T_SYM;
1076
gsydata->d_version = EV_CURRENT;
1077
}
1078
}
1079
1080
/*
1081
* Create two Elf_Data for .strtab, one for local symbol name
1082
* and another for globals. Same as .symtab, local symbol names
1083
* appear first.
1084
*/
1085
st_buf = st->buf;
1086
if ((lstdata = elf_newdata(st->os)) == NULL)
1087
errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1088
elf_errmsg(-1));
1089
lstdata->d_align = 1;
1090
lstdata->d_off = 0;
1091
lstdata->d_buf = st_buf->l.buf;
1092
lstdata->d_size = st_buf->l.sz;
1093
lstdata->d_type = ELF_T_BYTE;
1094
lstdata->d_version = EV_CURRENT;
1095
1096
if (st_buf->g.sz > 0) {
1097
if ((gstdata = elf_newdata(st->os)) == NULL)
1098
errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
1099
elf_errmsg(-1));
1100
gstdata->d_align = 1;
1101
gstdata->d_off = lstdata->d_size;
1102
gstdata->d_buf = st_buf->g.buf;
1103
gstdata->d_size = st_buf->g.sz;
1104
gstdata->d_type = ELF_T_BYTE;
1105
gstdata->d_version = EV_CURRENT;
1106
}
1107
1108
shy.sh_addr = 0;
1109
shy.sh_addralign = (ecp->oec == ELFCLASS32 ? 4 : 8);
1110
shy.sh_size = sy->sz;
1111
shy.sh_type = SHT_SYMTAB;
1112
shy.sh_flags = 0;
1113
shy.sh_entsize = gelf_fsize(ecp->eout, ELF_T_SYM, 1,
1114
EV_CURRENT);
1115
/*
1116
* According to SYSV abi, here sh_info is one greater than
1117
* the symbol table index of the last local symbol(binding
1118
* STB_LOCAL).
1119
*/
1120
shy.sh_info = sy_buf->nls;
1121
1122
sht.sh_addr = 0;
1123
sht.sh_addralign = 1;
1124
sht.sh_size = st->sz;
1125
sht.sh_type = SHT_STRTAB;
1126
sht.sh_flags = 0;
1127
sht.sh_entsize = 0;
1128
sht.sh_info = 0;
1129
sht.sh_link = 0;
1130
1131
if (!gelf_update_shdr(sy->os, &shy))
1132
errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1133
elf_errmsg(-1));
1134
if (!gelf_update_shdr(st->os, &sht))
1135
errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1136
elf_errmsg(-1));
1137
}
1138
1139
void
1140
add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
1141
unsigned int op)
1142
{
1143
struct symop *s;
1144
1145
assert (name != NULL);
1146
STAILQ_FOREACH(s, &ecp->v_symop, symop_list)
1147
if (!strcmp(name, s->name))
1148
goto found;
1149
1150
if ((s = calloc(1, sizeof(*s))) == NULL)
1151
errx(EXIT_FAILURE, "not enough memory");
1152
STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list);
1153
s->name = name;
1154
found:
1155
if (op == SYMOP_REDEF)
1156
s->newname = newname;
1157
s->op |= op;
1158
}
1159
1160
struct symop *
1161
lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1162
{
1163
struct symop *s, *ret;
1164
const char *pattern;
1165
1166
STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1167
if ((s->op & op) == 0)
1168
continue;
1169
if (name == NULL || !strcmp(name, s->name))
1170
return (s);
1171
if ((ecp->flags & WILDCARD) == 0)
1172
continue;
1173
1174
/* Handle wildcards. */
1175
pattern = s->name;
1176
if (pattern[0] == '!') {
1177
/* Negative match. */
1178
pattern++;
1179
ret = NULL;
1180
} else {
1181
/* Regular wildcard match. */
1182
ret = s;
1183
}
1184
if (!fnmatch(pattern, name, 0))
1185
return (ret);
1186
}
1187
1188
return (NULL);
1189
}
1190
1191
static int
1192
lookup_exact_string(hash_head *buckets, const char *buf, const char *s)
1193
{
1194
struct sthash *sh;
1195
uint32_t hash;
1196
1197
hash = str_hash(s);
1198
LIST_FOREACH(sh, &buckets[hash], sh_next)
1199
if (strcmp(buf + sh->sh_off, s) == 0)
1200
return sh->sh_off;
1201
return (-1);
1202
}
1203
1204
uint32_t
1205
str_hash(const char *s)
1206
{
1207
uint32_t hash;
1208
1209
for (hash = 2166136261UL; *s; s++)
1210
hash = (hash ^ *s) * 16777619;
1211
1212
return (hash & (STHASHSIZE - 1));
1213
}
1214
1215