1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * elf.c - ELF access library
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Adapted from kpatch (https://github.com/dynup/kpatch):
6*4882a593Smuzhiyun * Copyright (C) 2013-2015 Josh Poimboeuf <jpoimboe@redhat.com>
7*4882a593Smuzhiyun * Copyright (C) 2014 Seth Jennings <sjenning@redhat.com>
8*4882a593Smuzhiyun */
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #include <sys/types.h>
11*4882a593Smuzhiyun #include <sys/stat.h>
12*4882a593Smuzhiyun #include <fcntl.h>
13*4882a593Smuzhiyun #include <stdio.h>
14*4882a593Smuzhiyun #include <stdlib.h>
15*4882a593Smuzhiyun #include <string.h>
16*4882a593Smuzhiyun #include <unistd.h>
17*4882a593Smuzhiyun #include <errno.h>
18*4882a593Smuzhiyun #include "builtin.h"
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include "elf.h"
21*4882a593Smuzhiyun #include "warn.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #define MAX_NAME_LEN 128
24*4882a593Smuzhiyun
str_hash(const char * str)25*4882a593Smuzhiyun static inline u32 str_hash(const char *str)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun return jhash(str, strlen(str), 0);
28*4882a593Smuzhiyun }
29*4882a593Smuzhiyun
elf_hash_bits(void)30*4882a593Smuzhiyun static inline int elf_hash_bits(void)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun return vmlinux ? ELF_HASH_BITS : 16;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #define elf_hash_add(hashtable, node, key) \
36*4882a593Smuzhiyun hlist_add_head(node, &hashtable[hash_min(key, elf_hash_bits())])
37*4882a593Smuzhiyun
elf_hash_init(struct hlist_head * table)38*4882a593Smuzhiyun static void elf_hash_init(struct hlist_head *table)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun __hash_init(table, 1U << elf_hash_bits());
41*4882a593Smuzhiyun }
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define elf_hash_for_each_possible(name, obj, member, key) \
44*4882a593Smuzhiyun hlist_for_each_entry(obj, &name[hash_min(key, elf_hash_bits())], member)
45*4882a593Smuzhiyun
rb_add(struct rb_root * tree,struct rb_node * node,int (* cmp)(struct rb_node *,const struct rb_node *))46*4882a593Smuzhiyun static void rb_add(struct rb_root *tree, struct rb_node *node,
47*4882a593Smuzhiyun int (*cmp)(struct rb_node *, const struct rb_node *))
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun struct rb_node **link = &tree->rb_node;
50*4882a593Smuzhiyun struct rb_node *parent = NULL;
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun while (*link) {
53*4882a593Smuzhiyun parent = *link;
54*4882a593Smuzhiyun if (cmp(node, parent) < 0)
55*4882a593Smuzhiyun link = &parent->rb_left;
56*4882a593Smuzhiyun else
57*4882a593Smuzhiyun link = &parent->rb_right;
58*4882a593Smuzhiyun }
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun rb_link_node(node, parent, link);
61*4882a593Smuzhiyun rb_insert_color(node, tree);
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun
rb_find_first(const struct rb_root * tree,const void * key,int (* cmp)(const void * key,const struct rb_node *))64*4882a593Smuzhiyun static struct rb_node *rb_find_first(const struct rb_root *tree, const void *key,
65*4882a593Smuzhiyun int (*cmp)(const void *key, const struct rb_node *))
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct rb_node *node = tree->rb_node;
68*4882a593Smuzhiyun struct rb_node *match = NULL;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun while (node) {
71*4882a593Smuzhiyun int c = cmp(key, node);
72*4882a593Smuzhiyun if (c <= 0) {
73*4882a593Smuzhiyun if (!c)
74*4882a593Smuzhiyun match = node;
75*4882a593Smuzhiyun node = node->rb_left;
76*4882a593Smuzhiyun } else if (c > 0) {
77*4882a593Smuzhiyun node = node->rb_right;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun return match;
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
rb_next_match(struct rb_node * node,const void * key,int (* cmp)(const void * key,const struct rb_node *))84*4882a593Smuzhiyun static struct rb_node *rb_next_match(struct rb_node *node, const void *key,
85*4882a593Smuzhiyun int (*cmp)(const void *key, const struct rb_node *))
86*4882a593Smuzhiyun {
87*4882a593Smuzhiyun node = rb_next(node);
88*4882a593Smuzhiyun if (node && cmp(key, node))
89*4882a593Smuzhiyun node = NULL;
90*4882a593Smuzhiyun return node;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define rb_for_each(tree, node, key, cmp) \
94*4882a593Smuzhiyun for ((node) = rb_find_first((tree), (key), (cmp)); \
95*4882a593Smuzhiyun (node); (node) = rb_next_match((node), (key), (cmp)))
96*4882a593Smuzhiyun
symbol_to_offset(struct rb_node * a,const struct rb_node * b)97*4882a593Smuzhiyun static int symbol_to_offset(struct rb_node *a, const struct rb_node *b)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun struct symbol *sa = rb_entry(a, struct symbol, node);
100*4882a593Smuzhiyun struct symbol *sb = rb_entry(b, struct symbol, node);
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun if (sa->offset < sb->offset)
103*4882a593Smuzhiyun return -1;
104*4882a593Smuzhiyun if (sa->offset > sb->offset)
105*4882a593Smuzhiyun return 1;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun if (sa->len < sb->len)
108*4882a593Smuzhiyun return -1;
109*4882a593Smuzhiyun if (sa->len > sb->len)
110*4882a593Smuzhiyun return 1;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun sa->alias = sb;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return 0;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
symbol_by_offset(const void * key,const struct rb_node * node)117*4882a593Smuzhiyun static int symbol_by_offset(const void *key, const struct rb_node *node)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun const struct symbol *s = rb_entry(node, struct symbol, node);
120*4882a593Smuzhiyun const unsigned long *o = key;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (*o < s->offset)
123*4882a593Smuzhiyun return -1;
124*4882a593Smuzhiyun if (*o >= s->offset + s->len)
125*4882a593Smuzhiyun return 1;
126*4882a593Smuzhiyun
127*4882a593Smuzhiyun return 0;
128*4882a593Smuzhiyun }
129*4882a593Smuzhiyun
find_section_by_name(const struct elf * elf,const char * name)130*4882a593Smuzhiyun struct section *find_section_by_name(const struct elf *elf, const char *name)
131*4882a593Smuzhiyun {
132*4882a593Smuzhiyun struct section *sec;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun elf_hash_for_each_possible(elf->section_name_hash, sec, name_hash, str_hash(name))
135*4882a593Smuzhiyun if (!strcmp(sec->name, name))
136*4882a593Smuzhiyun return sec;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun return NULL;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun
find_section_by_index(struct elf * elf,unsigned int idx)141*4882a593Smuzhiyun static struct section *find_section_by_index(struct elf *elf,
142*4882a593Smuzhiyun unsigned int idx)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun struct section *sec;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun elf_hash_for_each_possible(elf->section_hash, sec, hash, idx)
147*4882a593Smuzhiyun if (sec->idx == idx)
148*4882a593Smuzhiyun return sec;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun return NULL;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
find_symbol_by_index(struct elf * elf,unsigned int idx)153*4882a593Smuzhiyun static struct symbol *find_symbol_by_index(struct elf *elf, unsigned int idx)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun struct symbol *sym;
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun elf_hash_for_each_possible(elf->symbol_hash, sym, hash, idx)
158*4882a593Smuzhiyun if (sym->idx == idx)
159*4882a593Smuzhiyun return sym;
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun return NULL;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
find_symbol_by_offset(struct section * sec,unsigned long offset)164*4882a593Smuzhiyun struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun struct rb_node *node;
167*4882a593Smuzhiyun
168*4882a593Smuzhiyun rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
169*4882a593Smuzhiyun struct symbol *s = rb_entry(node, struct symbol, node);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (s->offset == offset && s->type != STT_SECTION)
172*4882a593Smuzhiyun return s;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun return NULL;
176*4882a593Smuzhiyun }
177*4882a593Smuzhiyun
find_func_by_offset(struct section * sec,unsigned long offset)178*4882a593Smuzhiyun struct symbol *find_func_by_offset(struct section *sec, unsigned long offset)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun struct rb_node *node;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
183*4882a593Smuzhiyun struct symbol *s = rb_entry(node, struct symbol, node);
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun if (s->offset == offset && s->type == STT_FUNC)
186*4882a593Smuzhiyun return s;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun return NULL;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
find_symbol_containing(const struct section * sec,unsigned long offset)192*4882a593Smuzhiyun struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset)
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun struct rb_node *node;
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
197*4882a593Smuzhiyun struct symbol *s = rb_entry(node, struct symbol, node);
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (s->type != STT_SECTION)
200*4882a593Smuzhiyun return s;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun return NULL;
204*4882a593Smuzhiyun }
205*4882a593Smuzhiyun
find_func_containing(struct section * sec,unsigned long offset)206*4882a593Smuzhiyun struct symbol *find_func_containing(struct section *sec, unsigned long offset)
207*4882a593Smuzhiyun {
208*4882a593Smuzhiyun struct rb_node *node;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun rb_for_each(&sec->symbol_tree, node, &offset, symbol_by_offset) {
211*4882a593Smuzhiyun struct symbol *s = rb_entry(node, struct symbol, node);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun if (s->type == STT_FUNC)
214*4882a593Smuzhiyun return s;
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun return NULL;
218*4882a593Smuzhiyun }
219*4882a593Smuzhiyun
find_symbol_by_name(const struct elf * elf,const char * name)220*4882a593Smuzhiyun struct symbol *find_symbol_by_name(const struct elf *elf, const char *name)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun struct symbol *sym;
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun elf_hash_for_each_possible(elf->symbol_name_hash, sym, name_hash, str_hash(name))
225*4882a593Smuzhiyun if (!strcmp(sym->name, name))
226*4882a593Smuzhiyun return sym;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun return NULL;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
find_reloc_by_dest_range(const struct elf * elf,struct section * sec,unsigned long offset,unsigned int len)231*4882a593Smuzhiyun struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
232*4882a593Smuzhiyun unsigned long offset, unsigned int len)
233*4882a593Smuzhiyun {
234*4882a593Smuzhiyun struct reloc *reloc, *r = NULL;
235*4882a593Smuzhiyun unsigned long o;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (!sec->reloc)
238*4882a593Smuzhiyun return NULL;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun sec = sec->reloc;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun for_offset_range(o, offset, offset + len) {
243*4882a593Smuzhiyun elf_hash_for_each_possible(elf->reloc_hash, reloc, hash,
244*4882a593Smuzhiyun sec_offset_hash(sec, o)) {
245*4882a593Smuzhiyun if (reloc->sec != sec)
246*4882a593Smuzhiyun continue;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun if (reloc->offset >= offset && reloc->offset < offset + len) {
249*4882a593Smuzhiyun if (!r || reloc->offset < r->offset)
250*4882a593Smuzhiyun r = reloc;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun if (r)
254*4882a593Smuzhiyun return r;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun return NULL;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun
find_reloc_by_dest(const struct elf * elf,struct section * sec,unsigned long offset)260*4882a593Smuzhiyun struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset)
261*4882a593Smuzhiyun {
262*4882a593Smuzhiyun return find_reloc_by_dest_range(elf, sec, offset, 1);
263*4882a593Smuzhiyun }
264*4882a593Smuzhiyun
read_sections(struct elf * elf)265*4882a593Smuzhiyun static int read_sections(struct elf *elf)
266*4882a593Smuzhiyun {
267*4882a593Smuzhiyun Elf_Scn *s = NULL;
268*4882a593Smuzhiyun struct section *sec;
269*4882a593Smuzhiyun size_t shstrndx, sections_nr;
270*4882a593Smuzhiyun int i;
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (elf_getshdrnum(elf->elf, §ions_nr)) {
273*4882a593Smuzhiyun WARN_ELF("elf_getshdrnum");
274*4882a593Smuzhiyun return -1;
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun if (elf_getshdrstrndx(elf->elf, &shstrndx)) {
278*4882a593Smuzhiyun WARN_ELF("elf_getshdrstrndx");
279*4882a593Smuzhiyun return -1;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun for (i = 0; i < sections_nr; i++) {
283*4882a593Smuzhiyun sec = malloc(sizeof(*sec));
284*4882a593Smuzhiyun if (!sec) {
285*4882a593Smuzhiyun perror("malloc");
286*4882a593Smuzhiyun return -1;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun memset(sec, 0, sizeof(*sec));
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun INIT_LIST_HEAD(&sec->symbol_list);
291*4882a593Smuzhiyun INIT_LIST_HEAD(&sec->reloc_list);
292*4882a593Smuzhiyun
293*4882a593Smuzhiyun s = elf_getscn(elf->elf, i);
294*4882a593Smuzhiyun if (!s) {
295*4882a593Smuzhiyun WARN_ELF("elf_getscn");
296*4882a593Smuzhiyun return -1;
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
299*4882a593Smuzhiyun sec->idx = elf_ndxscn(s);
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun if (!gelf_getshdr(s, &sec->sh)) {
302*4882a593Smuzhiyun WARN_ELF("gelf_getshdr");
303*4882a593Smuzhiyun return -1;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun sec->name = elf_strptr(elf->elf, shstrndx, sec->sh.sh_name);
307*4882a593Smuzhiyun if (!sec->name) {
308*4882a593Smuzhiyun WARN_ELF("elf_strptr");
309*4882a593Smuzhiyun return -1;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun if (sec->sh.sh_size != 0) {
313*4882a593Smuzhiyun sec->data = elf_getdata(s, NULL);
314*4882a593Smuzhiyun if (!sec->data) {
315*4882a593Smuzhiyun WARN_ELF("elf_getdata");
316*4882a593Smuzhiyun return -1;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun if (sec->data->d_off != 0 ||
319*4882a593Smuzhiyun sec->data->d_size != sec->sh.sh_size) {
320*4882a593Smuzhiyun WARN("unexpected data attributes for %s",
321*4882a593Smuzhiyun sec->name);
322*4882a593Smuzhiyun return -1;
323*4882a593Smuzhiyun }
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun sec->len = sec->sh.sh_size;
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun list_add_tail(&sec->list, &elf->sections);
328*4882a593Smuzhiyun elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
329*4882a593Smuzhiyun elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun if (stats)
333*4882a593Smuzhiyun printf("nr_sections: %lu\n", (unsigned long)sections_nr);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /* sanity check, one more call to elf_nextscn() should return NULL */
336*4882a593Smuzhiyun if (elf_nextscn(elf->elf, s)) {
337*4882a593Smuzhiyun WARN("section entry mismatch");
338*4882a593Smuzhiyun return -1;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun return 0;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
elf_add_symbol(struct elf * elf,struct symbol * sym)344*4882a593Smuzhiyun static void elf_add_symbol(struct elf *elf, struct symbol *sym)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun struct list_head *entry;
347*4882a593Smuzhiyun struct rb_node *pnode;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun sym->alias = sym;
350*4882a593Smuzhiyun
351*4882a593Smuzhiyun sym->type = GELF_ST_TYPE(sym->sym.st_info);
352*4882a593Smuzhiyun sym->bind = GELF_ST_BIND(sym->sym.st_info);
353*4882a593Smuzhiyun
354*4882a593Smuzhiyun sym->offset = sym->sym.st_value;
355*4882a593Smuzhiyun sym->len = sym->sym.st_size;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun rb_add(&sym->sec->symbol_tree, &sym->node, symbol_to_offset);
358*4882a593Smuzhiyun pnode = rb_prev(&sym->node);
359*4882a593Smuzhiyun if (pnode)
360*4882a593Smuzhiyun entry = &rb_entry(pnode, struct symbol, node)->list;
361*4882a593Smuzhiyun else
362*4882a593Smuzhiyun entry = &sym->sec->symbol_list;
363*4882a593Smuzhiyun list_add(&sym->list, entry);
364*4882a593Smuzhiyun elf_hash_add(elf->symbol_hash, &sym->hash, sym->idx);
365*4882a593Smuzhiyun elf_hash_add(elf->symbol_name_hash, &sym->name_hash, str_hash(sym->name));
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun /*
368*4882a593Smuzhiyun * Don't store empty STT_NOTYPE symbols in the rbtree. They
369*4882a593Smuzhiyun * can exist within a function, confusing the sorting.
370*4882a593Smuzhiyun */
371*4882a593Smuzhiyun if (!sym->len)
372*4882a593Smuzhiyun rb_erase(&sym->node, &sym->sec->symbol_tree);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
read_symbols(struct elf * elf)375*4882a593Smuzhiyun static int read_symbols(struct elf *elf)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun struct section *symtab, *symtab_shndx, *sec;
378*4882a593Smuzhiyun struct symbol *sym, *pfunc;
379*4882a593Smuzhiyun int symbols_nr, i;
380*4882a593Smuzhiyun char *coldstr;
381*4882a593Smuzhiyun Elf_Data *shndx_data = NULL;
382*4882a593Smuzhiyun Elf32_Word shndx;
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun symtab = find_section_by_name(elf, ".symtab");
385*4882a593Smuzhiyun if (!symtab) {
386*4882a593Smuzhiyun /*
387*4882a593Smuzhiyun * A missing symbol table is actually possible if it's an empty
388*4882a593Smuzhiyun * .o file. This can happen for thunk_64.o.
389*4882a593Smuzhiyun */
390*4882a593Smuzhiyun return 0;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
394*4882a593Smuzhiyun if (symtab_shndx)
395*4882a593Smuzhiyun shndx_data = symtab_shndx->data;
396*4882a593Smuzhiyun
397*4882a593Smuzhiyun symbols_nr = symtab->sh.sh_size / symtab->sh.sh_entsize;
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun for (i = 0; i < symbols_nr; i++) {
400*4882a593Smuzhiyun sym = malloc(sizeof(*sym));
401*4882a593Smuzhiyun if (!sym) {
402*4882a593Smuzhiyun perror("malloc");
403*4882a593Smuzhiyun return -1;
404*4882a593Smuzhiyun }
405*4882a593Smuzhiyun memset(sym, 0, sizeof(*sym));
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun sym->idx = i;
408*4882a593Smuzhiyun
409*4882a593Smuzhiyun if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym,
410*4882a593Smuzhiyun &shndx)) {
411*4882a593Smuzhiyun WARN_ELF("gelf_getsymshndx");
412*4882a593Smuzhiyun goto err;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun
415*4882a593Smuzhiyun sym->name = elf_strptr(elf->elf, symtab->sh.sh_link,
416*4882a593Smuzhiyun sym->sym.st_name);
417*4882a593Smuzhiyun if (!sym->name) {
418*4882a593Smuzhiyun WARN_ELF("elf_strptr");
419*4882a593Smuzhiyun goto err;
420*4882a593Smuzhiyun }
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun if ((sym->sym.st_shndx > SHN_UNDEF &&
423*4882a593Smuzhiyun sym->sym.st_shndx < SHN_LORESERVE) ||
424*4882a593Smuzhiyun (shndx_data && sym->sym.st_shndx == SHN_XINDEX)) {
425*4882a593Smuzhiyun if (sym->sym.st_shndx != SHN_XINDEX)
426*4882a593Smuzhiyun shndx = sym->sym.st_shndx;
427*4882a593Smuzhiyun
428*4882a593Smuzhiyun sym->sec = find_section_by_index(elf, shndx);
429*4882a593Smuzhiyun if (!sym->sec) {
430*4882a593Smuzhiyun WARN("couldn't find section for symbol %s",
431*4882a593Smuzhiyun sym->name);
432*4882a593Smuzhiyun goto err;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun if (GELF_ST_TYPE(sym->sym.st_info) == STT_SECTION) {
435*4882a593Smuzhiyun sym->name = sym->sec->name;
436*4882a593Smuzhiyun sym->sec->sym = sym;
437*4882a593Smuzhiyun }
438*4882a593Smuzhiyun } else
439*4882a593Smuzhiyun sym->sec = find_section_by_index(elf, 0);
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun elf_add_symbol(elf, sym);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (stats)
445*4882a593Smuzhiyun printf("nr_symbols: %lu\n", (unsigned long)symbols_nr);
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun /* Create parent/child links for any cold subfunctions */
448*4882a593Smuzhiyun list_for_each_entry(sec, &elf->sections, list) {
449*4882a593Smuzhiyun list_for_each_entry(sym, &sec->symbol_list, list) {
450*4882a593Smuzhiyun char pname[MAX_NAME_LEN + 1];
451*4882a593Smuzhiyun size_t pnamelen;
452*4882a593Smuzhiyun if (sym->type != STT_FUNC)
453*4882a593Smuzhiyun continue;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun if (sym->pfunc == NULL)
456*4882a593Smuzhiyun sym->pfunc = sym;
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun if (sym->cfunc == NULL)
459*4882a593Smuzhiyun sym->cfunc = sym;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun coldstr = strstr(sym->name, ".cold");
462*4882a593Smuzhiyun if (!coldstr)
463*4882a593Smuzhiyun continue;
464*4882a593Smuzhiyun
465*4882a593Smuzhiyun pnamelen = coldstr - sym->name;
466*4882a593Smuzhiyun if (pnamelen > MAX_NAME_LEN) {
467*4882a593Smuzhiyun WARN("%s(): parent function name exceeds maximum length of %d characters",
468*4882a593Smuzhiyun sym->name, MAX_NAME_LEN);
469*4882a593Smuzhiyun return -1;
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun strncpy(pname, sym->name, pnamelen);
473*4882a593Smuzhiyun pname[pnamelen] = '\0';
474*4882a593Smuzhiyun pfunc = find_symbol_by_name(elf, pname);
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun if (!pfunc) {
477*4882a593Smuzhiyun WARN("%s(): can't find parent function",
478*4882a593Smuzhiyun sym->name);
479*4882a593Smuzhiyun return -1;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun sym->pfunc = pfunc;
483*4882a593Smuzhiyun pfunc->cfunc = sym;
484*4882a593Smuzhiyun
485*4882a593Smuzhiyun /*
486*4882a593Smuzhiyun * Unfortunately, -fnoreorder-functions puts the child
487*4882a593Smuzhiyun * inside the parent. Remove the overlap so we can
488*4882a593Smuzhiyun * have sane assumptions.
489*4882a593Smuzhiyun *
490*4882a593Smuzhiyun * Note that pfunc->len now no longer matches
491*4882a593Smuzhiyun * pfunc->sym.st_size.
492*4882a593Smuzhiyun */
493*4882a593Smuzhiyun if (sym->sec == pfunc->sec &&
494*4882a593Smuzhiyun sym->offset >= pfunc->offset &&
495*4882a593Smuzhiyun sym->offset + sym->len == pfunc->offset + pfunc->len) {
496*4882a593Smuzhiyun pfunc->len -= sym->len;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun }
499*4882a593Smuzhiyun }
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun return 0;
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun err:
504*4882a593Smuzhiyun free(sym);
505*4882a593Smuzhiyun return -1;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
508*4882a593Smuzhiyun static struct section *elf_create_reloc_section(struct elf *elf,
509*4882a593Smuzhiyun struct section *base,
510*4882a593Smuzhiyun int reltype);
511*4882a593Smuzhiyun
elf_add_reloc(struct elf * elf,struct section * sec,unsigned long offset,unsigned int type,struct symbol * sym,s64 addend)512*4882a593Smuzhiyun int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
513*4882a593Smuzhiyun unsigned int type, struct symbol *sym, s64 addend)
514*4882a593Smuzhiyun {
515*4882a593Smuzhiyun struct reloc *reloc;
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun if (!sec->reloc && !elf_create_reloc_section(elf, sec, SHT_RELA))
518*4882a593Smuzhiyun return -1;
519*4882a593Smuzhiyun
520*4882a593Smuzhiyun reloc = malloc(sizeof(*reloc));
521*4882a593Smuzhiyun if (!reloc) {
522*4882a593Smuzhiyun perror("malloc");
523*4882a593Smuzhiyun return -1;
524*4882a593Smuzhiyun }
525*4882a593Smuzhiyun memset(reloc, 0, sizeof(*reloc));
526*4882a593Smuzhiyun
527*4882a593Smuzhiyun reloc->sec = sec->reloc;
528*4882a593Smuzhiyun reloc->offset = offset;
529*4882a593Smuzhiyun reloc->type = type;
530*4882a593Smuzhiyun reloc->sym = sym;
531*4882a593Smuzhiyun reloc->addend = addend;
532*4882a593Smuzhiyun
533*4882a593Smuzhiyun list_add_tail(&reloc->list, &sec->reloc->reloc_list);
534*4882a593Smuzhiyun elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun sec->reloc->changed = true;
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun return 0;
539*4882a593Smuzhiyun }
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /*
542*4882a593Smuzhiyun * Ensure that any reloc section containing references to @sym is marked
543*4882a593Smuzhiyun * changed such that it will get re-generated in elf_rebuild_reloc_sections()
544*4882a593Smuzhiyun * with the new symbol index.
545*4882a593Smuzhiyun */
elf_dirty_reloc_sym(struct elf * elf,struct symbol * sym)546*4882a593Smuzhiyun static void elf_dirty_reloc_sym(struct elf *elf, struct symbol *sym)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun struct section *sec;
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun list_for_each_entry(sec, &elf->sections, list) {
551*4882a593Smuzhiyun struct reloc *reloc;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun if (sec->changed)
554*4882a593Smuzhiyun continue;
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun list_for_each_entry(reloc, &sec->reloc_list, list) {
557*4882a593Smuzhiyun if (reloc->sym == sym) {
558*4882a593Smuzhiyun sec->changed = true;
559*4882a593Smuzhiyun break;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun }
563*4882a593Smuzhiyun }
564*4882a593Smuzhiyun
565*4882a593Smuzhiyun /*
566*4882a593Smuzhiyun * The libelf API is terrible; gelf_update_sym*() takes a data block relative
567*4882a593Smuzhiyun * index value, *NOT* the symbol index. As such, iterate the data blocks and
568*4882a593Smuzhiyun * adjust index until it fits.
569*4882a593Smuzhiyun *
570*4882a593Smuzhiyun * If no data block is found, allow adding a new data block provided the index
571*4882a593Smuzhiyun * is only one past the end.
572*4882a593Smuzhiyun */
elf_update_symbol(struct elf * elf,struct section * symtab,struct section * symtab_shndx,struct symbol * sym)573*4882a593Smuzhiyun static int elf_update_symbol(struct elf *elf, struct section *symtab,
574*4882a593Smuzhiyun struct section *symtab_shndx, struct symbol *sym)
575*4882a593Smuzhiyun {
576*4882a593Smuzhiyun Elf32_Word shndx = sym->sec ? sym->sec->idx : SHN_UNDEF;
577*4882a593Smuzhiyun Elf_Data *symtab_data = NULL, *shndx_data = NULL;
578*4882a593Smuzhiyun Elf64_Xword entsize = symtab->sh.sh_entsize;
579*4882a593Smuzhiyun int max_idx, idx = sym->idx;
580*4882a593Smuzhiyun Elf_Scn *s, *t = NULL;
581*4882a593Smuzhiyun bool is_special_shndx = sym->sym.st_shndx >= SHN_LORESERVE &&
582*4882a593Smuzhiyun sym->sym.st_shndx != SHN_XINDEX;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun if (is_special_shndx)
585*4882a593Smuzhiyun shndx = sym->sym.st_shndx;
586*4882a593Smuzhiyun
587*4882a593Smuzhiyun s = elf_getscn(elf->elf, symtab->idx);
588*4882a593Smuzhiyun if (!s) {
589*4882a593Smuzhiyun WARN_ELF("elf_getscn");
590*4882a593Smuzhiyun return -1;
591*4882a593Smuzhiyun }
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun if (symtab_shndx) {
594*4882a593Smuzhiyun t = elf_getscn(elf->elf, symtab_shndx->idx);
595*4882a593Smuzhiyun if (!t) {
596*4882a593Smuzhiyun WARN_ELF("elf_getscn");
597*4882a593Smuzhiyun return -1;
598*4882a593Smuzhiyun }
599*4882a593Smuzhiyun }
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun for (;;) {
602*4882a593Smuzhiyun /* get next data descriptor for the relevant sections */
603*4882a593Smuzhiyun symtab_data = elf_getdata(s, symtab_data);
604*4882a593Smuzhiyun if (t)
605*4882a593Smuzhiyun shndx_data = elf_getdata(t, shndx_data);
606*4882a593Smuzhiyun
607*4882a593Smuzhiyun /* end-of-list */
608*4882a593Smuzhiyun if (!symtab_data) {
609*4882a593Smuzhiyun void *buf;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun if (idx) {
612*4882a593Smuzhiyun /* we don't do holes in symbol tables */
613*4882a593Smuzhiyun WARN("index out of range");
614*4882a593Smuzhiyun return -1;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun /* if @idx == 0, it's the next contiguous entry, create it */
618*4882a593Smuzhiyun symtab_data = elf_newdata(s);
619*4882a593Smuzhiyun if (t)
620*4882a593Smuzhiyun shndx_data = elf_newdata(t);
621*4882a593Smuzhiyun
622*4882a593Smuzhiyun buf = calloc(1, entsize);
623*4882a593Smuzhiyun if (!buf) {
624*4882a593Smuzhiyun WARN("malloc");
625*4882a593Smuzhiyun return -1;
626*4882a593Smuzhiyun }
627*4882a593Smuzhiyun
628*4882a593Smuzhiyun symtab_data->d_buf = buf;
629*4882a593Smuzhiyun symtab_data->d_size = entsize;
630*4882a593Smuzhiyun symtab_data->d_align = 1;
631*4882a593Smuzhiyun symtab_data->d_type = ELF_T_SYM;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun symtab->sh.sh_size += entsize;
634*4882a593Smuzhiyun symtab->changed = true;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun if (t) {
637*4882a593Smuzhiyun shndx_data->d_buf = &sym->sec->idx;
638*4882a593Smuzhiyun shndx_data->d_size = sizeof(Elf32_Word);
639*4882a593Smuzhiyun shndx_data->d_align = sizeof(Elf32_Word);
640*4882a593Smuzhiyun shndx_data->d_type = ELF_T_WORD;
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun symtab_shndx->sh.sh_size += sizeof(Elf32_Word);
643*4882a593Smuzhiyun symtab_shndx->changed = true;
644*4882a593Smuzhiyun }
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun break;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun /* empty blocks should not happen */
650*4882a593Smuzhiyun if (!symtab_data->d_size) {
651*4882a593Smuzhiyun WARN("zero size data");
652*4882a593Smuzhiyun return -1;
653*4882a593Smuzhiyun }
654*4882a593Smuzhiyun
655*4882a593Smuzhiyun /* is this the right block? */
656*4882a593Smuzhiyun max_idx = symtab_data->d_size / entsize;
657*4882a593Smuzhiyun if (idx < max_idx)
658*4882a593Smuzhiyun break;
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun /* adjust index and try again */
661*4882a593Smuzhiyun idx -= max_idx;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun
664*4882a593Smuzhiyun /* something went side-ways */
665*4882a593Smuzhiyun if (idx < 0) {
666*4882a593Smuzhiyun WARN("negative index");
667*4882a593Smuzhiyun return -1;
668*4882a593Smuzhiyun }
669*4882a593Smuzhiyun
670*4882a593Smuzhiyun /* setup extended section index magic and write the symbol */
671*4882a593Smuzhiyun if ((shndx >= SHN_UNDEF && shndx < SHN_LORESERVE) || is_special_shndx) {
672*4882a593Smuzhiyun sym->sym.st_shndx = shndx;
673*4882a593Smuzhiyun if (!shndx_data)
674*4882a593Smuzhiyun shndx = 0;
675*4882a593Smuzhiyun } else {
676*4882a593Smuzhiyun sym->sym.st_shndx = SHN_XINDEX;
677*4882a593Smuzhiyun if (!shndx_data) {
678*4882a593Smuzhiyun WARN("no .symtab_shndx");
679*4882a593Smuzhiyun return -1;
680*4882a593Smuzhiyun }
681*4882a593Smuzhiyun }
682*4882a593Smuzhiyun
683*4882a593Smuzhiyun if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)) {
684*4882a593Smuzhiyun WARN_ELF("gelf_update_symshndx");
685*4882a593Smuzhiyun return -1;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
688*4882a593Smuzhiyun return 0;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun
691*4882a593Smuzhiyun static struct symbol *
elf_create_section_symbol(struct elf * elf,struct section * sec)692*4882a593Smuzhiyun elf_create_section_symbol(struct elf *elf, struct section *sec)
693*4882a593Smuzhiyun {
694*4882a593Smuzhiyun struct section *symtab, *symtab_shndx;
695*4882a593Smuzhiyun Elf32_Word first_non_local, new_idx;
696*4882a593Smuzhiyun struct symbol *sym, *old;
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun symtab = find_section_by_name(elf, ".symtab");
699*4882a593Smuzhiyun if (symtab) {
700*4882a593Smuzhiyun symtab_shndx = find_section_by_name(elf, ".symtab_shndx");
701*4882a593Smuzhiyun } else {
702*4882a593Smuzhiyun WARN("no .symtab");
703*4882a593Smuzhiyun return NULL;
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun sym = calloc(1, sizeof(*sym));
707*4882a593Smuzhiyun if (!sym) {
708*4882a593Smuzhiyun perror("malloc");
709*4882a593Smuzhiyun return NULL;
710*4882a593Smuzhiyun }
711*4882a593Smuzhiyun
712*4882a593Smuzhiyun sym->name = sec->name;
713*4882a593Smuzhiyun sym->sec = sec;
714*4882a593Smuzhiyun
715*4882a593Smuzhiyun // st_name 0
716*4882a593Smuzhiyun sym->sym.st_info = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
717*4882a593Smuzhiyun // st_other 0
718*4882a593Smuzhiyun // st_value 0
719*4882a593Smuzhiyun // st_size 0
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun /*
722*4882a593Smuzhiyun * Move the first global symbol, as per sh_info, into a new, higher
723*4882a593Smuzhiyun * symbol index. This fees up a spot for a new local symbol.
724*4882a593Smuzhiyun */
725*4882a593Smuzhiyun first_non_local = symtab->sh.sh_info;
726*4882a593Smuzhiyun new_idx = symtab->sh.sh_size / symtab->sh.sh_entsize;
727*4882a593Smuzhiyun old = find_symbol_by_index(elf, first_non_local);
728*4882a593Smuzhiyun if (old) {
729*4882a593Smuzhiyun old->idx = new_idx;
730*4882a593Smuzhiyun
731*4882a593Smuzhiyun hlist_del(&old->hash);
732*4882a593Smuzhiyun elf_hash_add(elf->symbol_hash, &old->hash, old->idx);
733*4882a593Smuzhiyun
734*4882a593Smuzhiyun elf_dirty_reloc_sym(elf, old);
735*4882a593Smuzhiyun
736*4882a593Smuzhiyun if (elf_update_symbol(elf, symtab, symtab_shndx, old)) {
737*4882a593Smuzhiyun WARN("elf_update_symbol move");
738*4882a593Smuzhiyun return NULL;
739*4882a593Smuzhiyun }
740*4882a593Smuzhiyun
741*4882a593Smuzhiyun new_idx = first_non_local;
742*4882a593Smuzhiyun }
743*4882a593Smuzhiyun
744*4882a593Smuzhiyun sym->idx = new_idx;
745*4882a593Smuzhiyun if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) {
746*4882a593Smuzhiyun WARN("elf_update_symbol");
747*4882a593Smuzhiyun return NULL;
748*4882a593Smuzhiyun }
749*4882a593Smuzhiyun
750*4882a593Smuzhiyun /*
751*4882a593Smuzhiyun * Either way, we added a LOCAL symbol.
752*4882a593Smuzhiyun */
753*4882a593Smuzhiyun symtab->sh.sh_info += 1;
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun elf_add_symbol(elf, sym);
756*4882a593Smuzhiyun
757*4882a593Smuzhiyun return sym;
758*4882a593Smuzhiyun }
759*4882a593Smuzhiyun
elf_add_reloc_to_insn(struct elf * elf,struct section * sec,unsigned long offset,unsigned int type,struct section * insn_sec,unsigned long insn_off)760*4882a593Smuzhiyun int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
761*4882a593Smuzhiyun unsigned long offset, unsigned int type,
762*4882a593Smuzhiyun struct section *insn_sec, unsigned long insn_off)
763*4882a593Smuzhiyun {
764*4882a593Smuzhiyun struct symbol *sym = insn_sec->sym;
765*4882a593Smuzhiyun int addend = insn_off;
766*4882a593Smuzhiyun
767*4882a593Smuzhiyun if (!sym) {
768*4882a593Smuzhiyun /*
769*4882a593Smuzhiyun * Due to how weak functions work, we must use section based
770*4882a593Smuzhiyun * relocations. Symbol based relocations would result in the
771*4882a593Smuzhiyun * weak and non-weak function annotations being overlaid on the
772*4882a593Smuzhiyun * non-weak function after linking.
773*4882a593Smuzhiyun */
774*4882a593Smuzhiyun sym = elf_create_section_symbol(elf, insn_sec);
775*4882a593Smuzhiyun if (!sym)
776*4882a593Smuzhiyun return -1;
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun insn_sec->sym = sym;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun return elf_add_reloc(elf, sec, offset, type, sym, addend);
782*4882a593Smuzhiyun }
783*4882a593Smuzhiyun
read_rel_reloc(struct section * sec,int i,struct reloc * reloc,unsigned int * symndx)784*4882a593Smuzhiyun static int read_rel_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
785*4882a593Smuzhiyun {
786*4882a593Smuzhiyun if (!gelf_getrel(sec->data, i, &reloc->rel)) {
787*4882a593Smuzhiyun WARN_ELF("gelf_getrel");
788*4882a593Smuzhiyun return -1;
789*4882a593Smuzhiyun }
790*4882a593Smuzhiyun reloc->type = GELF_R_TYPE(reloc->rel.r_info);
791*4882a593Smuzhiyun reloc->addend = 0;
792*4882a593Smuzhiyun reloc->offset = reloc->rel.r_offset;
793*4882a593Smuzhiyun *symndx = GELF_R_SYM(reloc->rel.r_info);
794*4882a593Smuzhiyun return 0;
795*4882a593Smuzhiyun }
796*4882a593Smuzhiyun
read_rela_reloc(struct section * sec,int i,struct reloc * reloc,unsigned int * symndx)797*4882a593Smuzhiyun static int read_rela_reloc(struct section *sec, int i, struct reloc *reloc, unsigned int *symndx)
798*4882a593Smuzhiyun {
799*4882a593Smuzhiyun if (!gelf_getrela(sec->data, i, &reloc->rela)) {
800*4882a593Smuzhiyun WARN_ELF("gelf_getrela");
801*4882a593Smuzhiyun return -1;
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun reloc->type = GELF_R_TYPE(reloc->rela.r_info);
804*4882a593Smuzhiyun reloc->addend = reloc->rela.r_addend;
805*4882a593Smuzhiyun reloc->offset = reloc->rela.r_offset;
806*4882a593Smuzhiyun *symndx = GELF_R_SYM(reloc->rela.r_info);
807*4882a593Smuzhiyun return 0;
808*4882a593Smuzhiyun }
809*4882a593Smuzhiyun
read_relocs(struct elf * elf)810*4882a593Smuzhiyun static int read_relocs(struct elf *elf)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun struct section *sec;
813*4882a593Smuzhiyun struct reloc *reloc;
814*4882a593Smuzhiyun int i;
815*4882a593Smuzhiyun unsigned int symndx;
816*4882a593Smuzhiyun unsigned long nr_reloc, max_reloc = 0, tot_reloc = 0;
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun list_for_each_entry(sec, &elf->sections, list) {
819*4882a593Smuzhiyun if ((sec->sh.sh_type != SHT_RELA) &&
820*4882a593Smuzhiyun (sec->sh.sh_type != SHT_REL))
821*4882a593Smuzhiyun continue;
822*4882a593Smuzhiyun
823*4882a593Smuzhiyun sec->base = find_section_by_index(elf, sec->sh.sh_info);
824*4882a593Smuzhiyun if (!sec->base) {
825*4882a593Smuzhiyun WARN("can't find base section for reloc section %s",
826*4882a593Smuzhiyun sec->name);
827*4882a593Smuzhiyun return -1;
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun sec->base->reloc = sec;
831*4882a593Smuzhiyun
832*4882a593Smuzhiyun nr_reloc = 0;
833*4882a593Smuzhiyun for (i = 0; i < sec->sh.sh_size / sec->sh.sh_entsize; i++) {
834*4882a593Smuzhiyun reloc = malloc(sizeof(*reloc));
835*4882a593Smuzhiyun if (!reloc) {
836*4882a593Smuzhiyun perror("malloc");
837*4882a593Smuzhiyun return -1;
838*4882a593Smuzhiyun }
839*4882a593Smuzhiyun memset(reloc, 0, sizeof(*reloc));
840*4882a593Smuzhiyun switch (sec->sh.sh_type) {
841*4882a593Smuzhiyun case SHT_REL:
842*4882a593Smuzhiyun if (read_rel_reloc(sec, i, reloc, &symndx))
843*4882a593Smuzhiyun return -1;
844*4882a593Smuzhiyun break;
845*4882a593Smuzhiyun case SHT_RELA:
846*4882a593Smuzhiyun if (read_rela_reloc(sec, i, reloc, &symndx))
847*4882a593Smuzhiyun return -1;
848*4882a593Smuzhiyun break;
849*4882a593Smuzhiyun default: return -1;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun reloc->sec = sec;
853*4882a593Smuzhiyun reloc->idx = i;
854*4882a593Smuzhiyun reloc->sym = find_symbol_by_index(elf, symndx);
855*4882a593Smuzhiyun if (!reloc->sym) {
856*4882a593Smuzhiyun WARN("can't find reloc entry symbol %d for %s",
857*4882a593Smuzhiyun symndx, sec->name);
858*4882a593Smuzhiyun return -1;
859*4882a593Smuzhiyun }
860*4882a593Smuzhiyun
861*4882a593Smuzhiyun list_add_tail(&reloc->list, &sec->reloc_list);
862*4882a593Smuzhiyun elf_hash_add(elf->reloc_hash, &reloc->hash, reloc_hash(reloc));
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun nr_reloc++;
865*4882a593Smuzhiyun }
866*4882a593Smuzhiyun max_reloc = max(max_reloc, nr_reloc);
867*4882a593Smuzhiyun tot_reloc += nr_reloc;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun
870*4882a593Smuzhiyun if (stats) {
871*4882a593Smuzhiyun printf("max_reloc: %lu\n", max_reloc);
872*4882a593Smuzhiyun printf("tot_reloc: %lu\n", tot_reloc);
873*4882a593Smuzhiyun }
874*4882a593Smuzhiyun
875*4882a593Smuzhiyun return 0;
876*4882a593Smuzhiyun }
877*4882a593Smuzhiyun
elf_open_read(const char * name,int flags)878*4882a593Smuzhiyun struct elf *elf_open_read(const char *name, int flags)
879*4882a593Smuzhiyun {
880*4882a593Smuzhiyun struct elf *elf;
881*4882a593Smuzhiyun Elf_Cmd cmd;
882*4882a593Smuzhiyun
883*4882a593Smuzhiyun elf_version(EV_CURRENT);
884*4882a593Smuzhiyun
885*4882a593Smuzhiyun elf = malloc(sizeof(*elf));
886*4882a593Smuzhiyun if (!elf) {
887*4882a593Smuzhiyun perror("malloc");
888*4882a593Smuzhiyun return NULL;
889*4882a593Smuzhiyun }
890*4882a593Smuzhiyun memset(elf, 0, offsetof(struct elf, sections));
891*4882a593Smuzhiyun
892*4882a593Smuzhiyun INIT_LIST_HEAD(&elf->sections);
893*4882a593Smuzhiyun
894*4882a593Smuzhiyun elf_hash_init(elf->symbol_hash);
895*4882a593Smuzhiyun elf_hash_init(elf->symbol_name_hash);
896*4882a593Smuzhiyun elf_hash_init(elf->section_hash);
897*4882a593Smuzhiyun elf_hash_init(elf->section_name_hash);
898*4882a593Smuzhiyun elf_hash_init(elf->reloc_hash);
899*4882a593Smuzhiyun
900*4882a593Smuzhiyun elf->fd = open(name, flags);
901*4882a593Smuzhiyun if (elf->fd == -1) {
902*4882a593Smuzhiyun fprintf(stderr, "objtool: Can't open '%s': %s\n",
903*4882a593Smuzhiyun name, strerror(errno));
904*4882a593Smuzhiyun goto err;
905*4882a593Smuzhiyun }
906*4882a593Smuzhiyun
907*4882a593Smuzhiyun if ((flags & O_ACCMODE) == O_RDONLY)
908*4882a593Smuzhiyun cmd = ELF_C_READ_MMAP;
909*4882a593Smuzhiyun else if ((flags & O_ACCMODE) == O_RDWR)
910*4882a593Smuzhiyun cmd = ELF_C_RDWR;
911*4882a593Smuzhiyun else /* O_WRONLY */
912*4882a593Smuzhiyun cmd = ELF_C_WRITE;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun elf->elf = elf_begin(elf->fd, cmd, NULL);
915*4882a593Smuzhiyun if (!elf->elf) {
916*4882a593Smuzhiyun WARN_ELF("elf_begin");
917*4882a593Smuzhiyun goto err;
918*4882a593Smuzhiyun }
919*4882a593Smuzhiyun
920*4882a593Smuzhiyun if (!gelf_getehdr(elf->elf, &elf->ehdr)) {
921*4882a593Smuzhiyun WARN_ELF("gelf_getehdr");
922*4882a593Smuzhiyun goto err;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun
925*4882a593Smuzhiyun if (read_sections(elf))
926*4882a593Smuzhiyun goto err;
927*4882a593Smuzhiyun
928*4882a593Smuzhiyun if (read_symbols(elf))
929*4882a593Smuzhiyun goto err;
930*4882a593Smuzhiyun
931*4882a593Smuzhiyun if (read_relocs(elf))
932*4882a593Smuzhiyun goto err;
933*4882a593Smuzhiyun
934*4882a593Smuzhiyun return elf;
935*4882a593Smuzhiyun
936*4882a593Smuzhiyun err:
937*4882a593Smuzhiyun elf_close(elf);
938*4882a593Smuzhiyun return NULL;
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun
elf_add_string(struct elf * elf,struct section * strtab,char * str)941*4882a593Smuzhiyun static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
942*4882a593Smuzhiyun {
943*4882a593Smuzhiyun Elf_Data *data;
944*4882a593Smuzhiyun Elf_Scn *s;
945*4882a593Smuzhiyun int len;
946*4882a593Smuzhiyun
947*4882a593Smuzhiyun if (!strtab)
948*4882a593Smuzhiyun strtab = find_section_by_name(elf, ".strtab");
949*4882a593Smuzhiyun if (!strtab) {
950*4882a593Smuzhiyun WARN("can't find .strtab section");
951*4882a593Smuzhiyun return -1;
952*4882a593Smuzhiyun }
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun s = elf_getscn(elf->elf, strtab->idx);
955*4882a593Smuzhiyun if (!s) {
956*4882a593Smuzhiyun WARN_ELF("elf_getscn");
957*4882a593Smuzhiyun return -1;
958*4882a593Smuzhiyun }
959*4882a593Smuzhiyun
960*4882a593Smuzhiyun data = elf_newdata(s);
961*4882a593Smuzhiyun if (!data) {
962*4882a593Smuzhiyun WARN_ELF("elf_newdata");
963*4882a593Smuzhiyun return -1;
964*4882a593Smuzhiyun }
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun data->d_buf = str;
967*4882a593Smuzhiyun data->d_size = strlen(str) + 1;
968*4882a593Smuzhiyun data->d_align = 1;
969*4882a593Smuzhiyun data->d_type = ELF_T_SYM;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun len = strtab->len;
972*4882a593Smuzhiyun strtab->len += data->d_size;
973*4882a593Smuzhiyun strtab->changed = true;
974*4882a593Smuzhiyun
975*4882a593Smuzhiyun return len;
976*4882a593Smuzhiyun }
977*4882a593Smuzhiyun
elf_create_section(struct elf * elf,const char * name,unsigned int sh_flags,size_t entsize,int nr)978*4882a593Smuzhiyun struct section *elf_create_section(struct elf *elf, const char *name,
979*4882a593Smuzhiyun unsigned int sh_flags, size_t entsize, int nr)
980*4882a593Smuzhiyun {
981*4882a593Smuzhiyun struct section *sec, *shstrtab;
982*4882a593Smuzhiyun size_t size = entsize * nr;
983*4882a593Smuzhiyun Elf_Scn *s;
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun sec = malloc(sizeof(*sec));
986*4882a593Smuzhiyun if (!sec) {
987*4882a593Smuzhiyun perror("malloc");
988*4882a593Smuzhiyun return NULL;
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun memset(sec, 0, sizeof(*sec));
991*4882a593Smuzhiyun
992*4882a593Smuzhiyun INIT_LIST_HEAD(&sec->symbol_list);
993*4882a593Smuzhiyun INIT_LIST_HEAD(&sec->reloc_list);
994*4882a593Smuzhiyun
995*4882a593Smuzhiyun s = elf_newscn(elf->elf);
996*4882a593Smuzhiyun if (!s) {
997*4882a593Smuzhiyun WARN_ELF("elf_newscn");
998*4882a593Smuzhiyun return NULL;
999*4882a593Smuzhiyun }
1000*4882a593Smuzhiyun
1001*4882a593Smuzhiyun sec->name = strdup(name);
1002*4882a593Smuzhiyun if (!sec->name) {
1003*4882a593Smuzhiyun perror("strdup");
1004*4882a593Smuzhiyun return NULL;
1005*4882a593Smuzhiyun }
1006*4882a593Smuzhiyun
1007*4882a593Smuzhiyun sec->idx = elf_ndxscn(s);
1008*4882a593Smuzhiyun sec->len = size;
1009*4882a593Smuzhiyun sec->changed = true;
1010*4882a593Smuzhiyun
1011*4882a593Smuzhiyun sec->data = elf_newdata(s);
1012*4882a593Smuzhiyun if (!sec->data) {
1013*4882a593Smuzhiyun WARN_ELF("elf_newdata");
1014*4882a593Smuzhiyun return NULL;
1015*4882a593Smuzhiyun }
1016*4882a593Smuzhiyun
1017*4882a593Smuzhiyun sec->data->d_size = size;
1018*4882a593Smuzhiyun sec->data->d_align = 1;
1019*4882a593Smuzhiyun
1020*4882a593Smuzhiyun if (size) {
1021*4882a593Smuzhiyun sec->data->d_buf = malloc(size);
1022*4882a593Smuzhiyun if (!sec->data->d_buf) {
1023*4882a593Smuzhiyun perror("malloc");
1024*4882a593Smuzhiyun return NULL;
1025*4882a593Smuzhiyun }
1026*4882a593Smuzhiyun memset(sec->data->d_buf, 0, size);
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun
1029*4882a593Smuzhiyun if (!gelf_getshdr(s, &sec->sh)) {
1030*4882a593Smuzhiyun WARN_ELF("gelf_getshdr");
1031*4882a593Smuzhiyun return NULL;
1032*4882a593Smuzhiyun }
1033*4882a593Smuzhiyun
1034*4882a593Smuzhiyun sec->sh.sh_size = size;
1035*4882a593Smuzhiyun sec->sh.sh_entsize = entsize;
1036*4882a593Smuzhiyun sec->sh.sh_type = SHT_PROGBITS;
1037*4882a593Smuzhiyun sec->sh.sh_addralign = 1;
1038*4882a593Smuzhiyun sec->sh.sh_flags = SHF_ALLOC | sh_flags;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun /* Add section name to .shstrtab (or .strtab for Clang) */
1041*4882a593Smuzhiyun shstrtab = find_section_by_name(elf, ".shstrtab");
1042*4882a593Smuzhiyun if (!shstrtab)
1043*4882a593Smuzhiyun shstrtab = find_section_by_name(elf, ".strtab");
1044*4882a593Smuzhiyun if (!shstrtab) {
1045*4882a593Smuzhiyun WARN("can't find .shstrtab or .strtab section");
1046*4882a593Smuzhiyun return NULL;
1047*4882a593Smuzhiyun }
1048*4882a593Smuzhiyun sec->sh.sh_name = elf_add_string(elf, shstrtab, sec->name);
1049*4882a593Smuzhiyun if (sec->sh.sh_name == -1)
1050*4882a593Smuzhiyun return NULL;
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun list_add_tail(&sec->list, &elf->sections);
1053*4882a593Smuzhiyun elf_hash_add(elf->section_hash, &sec->hash, sec->idx);
1054*4882a593Smuzhiyun elf_hash_add(elf->section_name_hash, &sec->name_hash, str_hash(sec->name));
1055*4882a593Smuzhiyun
1056*4882a593Smuzhiyun elf->changed = true;
1057*4882a593Smuzhiyun
1058*4882a593Smuzhiyun return sec;
1059*4882a593Smuzhiyun }
1060*4882a593Smuzhiyun
elf_create_rel_reloc_section(struct elf * elf,struct section * base)1061*4882a593Smuzhiyun static struct section *elf_create_rel_reloc_section(struct elf *elf, struct section *base)
1062*4882a593Smuzhiyun {
1063*4882a593Smuzhiyun char *relocname;
1064*4882a593Smuzhiyun struct section *sec;
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun relocname = malloc(strlen(base->name) + strlen(".rel") + 1);
1067*4882a593Smuzhiyun if (!relocname) {
1068*4882a593Smuzhiyun perror("malloc");
1069*4882a593Smuzhiyun return NULL;
1070*4882a593Smuzhiyun }
1071*4882a593Smuzhiyun strcpy(relocname, ".rel");
1072*4882a593Smuzhiyun strcat(relocname, base->name);
1073*4882a593Smuzhiyun
1074*4882a593Smuzhiyun sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rel), 0);
1075*4882a593Smuzhiyun free(relocname);
1076*4882a593Smuzhiyun if (!sec)
1077*4882a593Smuzhiyun return NULL;
1078*4882a593Smuzhiyun
1079*4882a593Smuzhiyun base->reloc = sec;
1080*4882a593Smuzhiyun sec->base = base;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun sec->sh.sh_type = SHT_REL;
1083*4882a593Smuzhiyun sec->sh.sh_addralign = 8;
1084*4882a593Smuzhiyun sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
1085*4882a593Smuzhiyun sec->sh.sh_info = base->idx;
1086*4882a593Smuzhiyun sec->sh.sh_flags = SHF_INFO_LINK;
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun return sec;
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun
elf_create_rela_reloc_section(struct elf * elf,struct section * base)1091*4882a593Smuzhiyun static struct section *elf_create_rela_reloc_section(struct elf *elf, struct section *base)
1092*4882a593Smuzhiyun {
1093*4882a593Smuzhiyun char *relocname;
1094*4882a593Smuzhiyun struct section *sec;
1095*4882a593Smuzhiyun
1096*4882a593Smuzhiyun relocname = malloc(strlen(base->name) + strlen(".rela") + 1);
1097*4882a593Smuzhiyun if (!relocname) {
1098*4882a593Smuzhiyun perror("malloc");
1099*4882a593Smuzhiyun return NULL;
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun strcpy(relocname, ".rela");
1102*4882a593Smuzhiyun strcat(relocname, base->name);
1103*4882a593Smuzhiyun
1104*4882a593Smuzhiyun sec = elf_create_section(elf, relocname, 0, sizeof(GElf_Rela), 0);
1105*4882a593Smuzhiyun free(relocname);
1106*4882a593Smuzhiyun if (!sec)
1107*4882a593Smuzhiyun return NULL;
1108*4882a593Smuzhiyun
1109*4882a593Smuzhiyun base->reloc = sec;
1110*4882a593Smuzhiyun sec->base = base;
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun sec->sh.sh_type = SHT_RELA;
1113*4882a593Smuzhiyun sec->sh.sh_addralign = 8;
1114*4882a593Smuzhiyun sec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
1115*4882a593Smuzhiyun sec->sh.sh_info = base->idx;
1116*4882a593Smuzhiyun sec->sh.sh_flags = SHF_INFO_LINK;
1117*4882a593Smuzhiyun
1118*4882a593Smuzhiyun return sec;
1119*4882a593Smuzhiyun }
1120*4882a593Smuzhiyun
elf_create_reloc_section(struct elf * elf,struct section * base,int reltype)1121*4882a593Smuzhiyun static struct section *elf_create_reloc_section(struct elf *elf,
1122*4882a593Smuzhiyun struct section *base,
1123*4882a593Smuzhiyun int reltype)
1124*4882a593Smuzhiyun {
1125*4882a593Smuzhiyun switch (reltype) {
1126*4882a593Smuzhiyun case SHT_REL: return elf_create_rel_reloc_section(elf, base);
1127*4882a593Smuzhiyun case SHT_RELA: return elf_create_rela_reloc_section(elf, base);
1128*4882a593Smuzhiyun default: return NULL;
1129*4882a593Smuzhiyun }
1130*4882a593Smuzhiyun }
1131*4882a593Smuzhiyun
elf_rebuild_rel_reloc_section(struct section * sec,int nr)1132*4882a593Smuzhiyun static int elf_rebuild_rel_reloc_section(struct section *sec, int nr)
1133*4882a593Smuzhiyun {
1134*4882a593Smuzhiyun struct reloc *reloc;
1135*4882a593Smuzhiyun int idx = 0, size;
1136*4882a593Smuzhiyun GElf_Rel *relocs;
1137*4882a593Smuzhiyun
1138*4882a593Smuzhiyun /* Allocate a buffer for relocations */
1139*4882a593Smuzhiyun size = nr * sizeof(*relocs);
1140*4882a593Smuzhiyun relocs = malloc(size);
1141*4882a593Smuzhiyun if (!relocs) {
1142*4882a593Smuzhiyun perror("malloc");
1143*4882a593Smuzhiyun return -1;
1144*4882a593Smuzhiyun }
1145*4882a593Smuzhiyun
1146*4882a593Smuzhiyun sec->data->d_buf = relocs;
1147*4882a593Smuzhiyun sec->data->d_size = size;
1148*4882a593Smuzhiyun
1149*4882a593Smuzhiyun sec->sh.sh_size = size;
1150*4882a593Smuzhiyun
1151*4882a593Smuzhiyun idx = 0;
1152*4882a593Smuzhiyun list_for_each_entry(reloc, &sec->reloc_list, list) {
1153*4882a593Smuzhiyun relocs[idx].r_offset = reloc->offset;
1154*4882a593Smuzhiyun relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1155*4882a593Smuzhiyun idx++;
1156*4882a593Smuzhiyun }
1157*4882a593Smuzhiyun
1158*4882a593Smuzhiyun return 0;
1159*4882a593Smuzhiyun }
1160*4882a593Smuzhiyun
elf_rebuild_rela_reloc_section(struct section * sec,int nr)1161*4882a593Smuzhiyun static int elf_rebuild_rela_reloc_section(struct section *sec, int nr)
1162*4882a593Smuzhiyun {
1163*4882a593Smuzhiyun struct reloc *reloc;
1164*4882a593Smuzhiyun int idx = 0, size;
1165*4882a593Smuzhiyun GElf_Rela *relocs;
1166*4882a593Smuzhiyun
1167*4882a593Smuzhiyun /* Allocate a buffer for relocations with addends */
1168*4882a593Smuzhiyun size = nr * sizeof(*relocs);
1169*4882a593Smuzhiyun relocs = malloc(size);
1170*4882a593Smuzhiyun if (!relocs) {
1171*4882a593Smuzhiyun perror("malloc");
1172*4882a593Smuzhiyun return -1;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun sec->data->d_buf = relocs;
1176*4882a593Smuzhiyun sec->data->d_size = size;
1177*4882a593Smuzhiyun
1178*4882a593Smuzhiyun sec->sh.sh_size = size;
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun idx = 0;
1181*4882a593Smuzhiyun list_for_each_entry(reloc, &sec->reloc_list, list) {
1182*4882a593Smuzhiyun relocs[idx].r_offset = reloc->offset;
1183*4882a593Smuzhiyun relocs[idx].r_addend = reloc->addend;
1184*4882a593Smuzhiyun relocs[idx].r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1185*4882a593Smuzhiyun idx++;
1186*4882a593Smuzhiyun }
1187*4882a593Smuzhiyun
1188*4882a593Smuzhiyun return 0;
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun
elf_rebuild_reloc_section(struct elf * elf,struct section * sec)1191*4882a593Smuzhiyun static int elf_rebuild_reloc_section(struct elf *elf, struct section *sec)
1192*4882a593Smuzhiyun {
1193*4882a593Smuzhiyun struct reloc *reloc;
1194*4882a593Smuzhiyun int nr;
1195*4882a593Smuzhiyun
1196*4882a593Smuzhiyun nr = 0;
1197*4882a593Smuzhiyun list_for_each_entry(reloc, &sec->reloc_list, list)
1198*4882a593Smuzhiyun nr++;
1199*4882a593Smuzhiyun
1200*4882a593Smuzhiyun switch (sec->sh.sh_type) {
1201*4882a593Smuzhiyun case SHT_REL: return elf_rebuild_rel_reloc_section(sec, nr);
1202*4882a593Smuzhiyun case SHT_RELA: return elf_rebuild_rela_reloc_section(sec, nr);
1203*4882a593Smuzhiyun default: return -1;
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun
elf_write_insn(struct elf * elf,struct section * sec,unsigned long offset,unsigned int len,const char * insn)1207*4882a593Smuzhiyun int elf_write_insn(struct elf *elf, struct section *sec,
1208*4882a593Smuzhiyun unsigned long offset, unsigned int len,
1209*4882a593Smuzhiyun const char *insn)
1210*4882a593Smuzhiyun {
1211*4882a593Smuzhiyun Elf_Data *data = sec->data;
1212*4882a593Smuzhiyun
1213*4882a593Smuzhiyun if (data->d_type != ELF_T_BYTE || data->d_off) {
1214*4882a593Smuzhiyun WARN("write to unexpected data for section: %s", sec->name);
1215*4882a593Smuzhiyun return -1;
1216*4882a593Smuzhiyun }
1217*4882a593Smuzhiyun
1218*4882a593Smuzhiyun memcpy(data->d_buf + offset, insn, len);
1219*4882a593Smuzhiyun elf_flagdata(data, ELF_C_SET, ELF_F_DIRTY);
1220*4882a593Smuzhiyun
1221*4882a593Smuzhiyun elf->changed = true;
1222*4882a593Smuzhiyun
1223*4882a593Smuzhiyun return 0;
1224*4882a593Smuzhiyun }
1225*4882a593Smuzhiyun
elf_write_reloc(struct elf * elf,struct reloc * reloc)1226*4882a593Smuzhiyun int elf_write_reloc(struct elf *elf, struct reloc *reloc)
1227*4882a593Smuzhiyun {
1228*4882a593Smuzhiyun struct section *sec = reloc->sec;
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun if (sec->sh.sh_type == SHT_REL) {
1231*4882a593Smuzhiyun reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1232*4882a593Smuzhiyun reloc->rel.r_offset = reloc->offset;
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun if (!gelf_update_rel(sec->data, reloc->idx, &reloc->rel)) {
1235*4882a593Smuzhiyun WARN_ELF("gelf_update_rel");
1236*4882a593Smuzhiyun return -1;
1237*4882a593Smuzhiyun }
1238*4882a593Smuzhiyun } else {
1239*4882a593Smuzhiyun reloc->rela.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
1240*4882a593Smuzhiyun reloc->rela.r_addend = reloc->addend;
1241*4882a593Smuzhiyun reloc->rela.r_offset = reloc->offset;
1242*4882a593Smuzhiyun
1243*4882a593Smuzhiyun if (!gelf_update_rela(sec->data, reloc->idx, &reloc->rela)) {
1244*4882a593Smuzhiyun WARN_ELF("gelf_update_rela");
1245*4882a593Smuzhiyun return -1;
1246*4882a593Smuzhiyun }
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun
1249*4882a593Smuzhiyun elf->changed = true;
1250*4882a593Smuzhiyun
1251*4882a593Smuzhiyun return 0;
1252*4882a593Smuzhiyun }
1253*4882a593Smuzhiyun
elf_write(struct elf * elf)1254*4882a593Smuzhiyun int elf_write(struct elf *elf)
1255*4882a593Smuzhiyun {
1256*4882a593Smuzhiyun struct section *sec;
1257*4882a593Smuzhiyun Elf_Scn *s;
1258*4882a593Smuzhiyun
1259*4882a593Smuzhiyun /* Update changed relocation sections and section headers: */
1260*4882a593Smuzhiyun list_for_each_entry(sec, &elf->sections, list) {
1261*4882a593Smuzhiyun if (sec->changed) {
1262*4882a593Smuzhiyun if (sec->base &&
1263*4882a593Smuzhiyun elf_rebuild_reloc_section(elf, sec)) {
1264*4882a593Smuzhiyun WARN("elf_rebuild_reloc_section");
1265*4882a593Smuzhiyun return -1;
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun s = elf_getscn(elf->elf, sec->idx);
1269*4882a593Smuzhiyun if (!s) {
1270*4882a593Smuzhiyun WARN_ELF("elf_getscn");
1271*4882a593Smuzhiyun return -1;
1272*4882a593Smuzhiyun }
1273*4882a593Smuzhiyun if (!gelf_update_shdr(s, &sec->sh)) {
1274*4882a593Smuzhiyun WARN_ELF("gelf_update_shdr");
1275*4882a593Smuzhiyun return -1;
1276*4882a593Smuzhiyun }
1277*4882a593Smuzhiyun
1278*4882a593Smuzhiyun sec->changed = false;
1279*4882a593Smuzhiyun elf->changed = true;
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun }
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun /* Make sure the new section header entries get updated properly. */
1284*4882a593Smuzhiyun elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY);
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun /* Write all changes to the file. */
1287*4882a593Smuzhiyun if (elf_update(elf->elf, ELF_C_WRITE) < 0) {
1288*4882a593Smuzhiyun WARN_ELF("elf_update");
1289*4882a593Smuzhiyun return -1;
1290*4882a593Smuzhiyun }
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun elf->changed = false;
1293*4882a593Smuzhiyun
1294*4882a593Smuzhiyun return 0;
1295*4882a593Smuzhiyun }
1296*4882a593Smuzhiyun
elf_close(struct elf * elf)1297*4882a593Smuzhiyun void elf_close(struct elf *elf)
1298*4882a593Smuzhiyun {
1299*4882a593Smuzhiyun struct section *sec, *tmpsec;
1300*4882a593Smuzhiyun struct symbol *sym, *tmpsym;
1301*4882a593Smuzhiyun struct reloc *reloc, *tmpreloc;
1302*4882a593Smuzhiyun
1303*4882a593Smuzhiyun if (elf->elf)
1304*4882a593Smuzhiyun elf_end(elf->elf);
1305*4882a593Smuzhiyun
1306*4882a593Smuzhiyun if (elf->fd > 0)
1307*4882a593Smuzhiyun close(elf->fd);
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun list_for_each_entry_safe(sec, tmpsec, &elf->sections, list) {
1310*4882a593Smuzhiyun list_for_each_entry_safe(sym, tmpsym, &sec->symbol_list, list) {
1311*4882a593Smuzhiyun list_del(&sym->list);
1312*4882a593Smuzhiyun hash_del(&sym->hash);
1313*4882a593Smuzhiyun free(sym);
1314*4882a593Smuzhiyun }
1315*4882a593Smuzhiyun list_for_each_entry_safe(reloc, tmpreloc, &sec->reloc_list, list) {
1316*4882a593Smuzhiyun list_del(&reloc->list);
1317*4882a593Smuzhiyun hash_del(&reloc->hash);
1318*4882a593Smuzhiyun free(reloc);
1319*4882a593Smuzhiyun }
1320*4882a593Smuzhiyun list_del(&sec->list);
1321*4882a593Smuzhiyun free(sec);
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun free(elf);
1325*4882a593Smuzhiyun }
1326