xref: /openbmc/linux/tools/objtool/include/objtool/elf.h (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1  /* SPDX-License-Identifier: GPL-2.0-or-later */
2  /*
3   * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
4   */
5  
6  #ifndef _OBJTOOL_ELF_H
7  #define _OBJTOOL_ELF_H
8  
9  #include <stdio.h>
10  #include <gelf.h>
11  #include <linux/list.h>
12  #include <linux/hashtable.h>
13  #include <linux/rbtree.h>
14  #include <linux/jhash.h>
15  #include <arch/elf.h>
16  
17  #ifdef LIBELF_USE_DEPRECATED
18  # define elf_getshdrnum    elf_getshnum
19  # define elf_getshdrstrndx elf_getshstrndx
20  #endif
21  
22  /*
23   * Fallback for systems without this "read, mmaping if possible" cmd.
24   */
25  #ifndef ELF_C_READ_MMAP
26  #define ELF_C_READ_MMAP ELF_C_READ
27  #endif
28  
29  struct elf_hash_node {
30  	struct elf_hash_node *next;
31  };
32  
33  struct section {
34  	struct list_head list;
35  	struct elf_hash_node hash;
36  	struct elf_hash_node name_hash;
37  	GElf_Shdr sh;
38  	struct rb_root_cached symbol_tree;
39  	struct list_head symbol_list;
40  	struct section *base, *rsec;
41  	struct symbol *sym;
42  	Elf_Data *data;
43  	char *name;
44  	int idx;
45  	bool _changed, text, rodata, noinstr, init, truncate;
46  	struct reloc *relocs;
47  };
48  
49  struct symbol {
50  	struct list_head list;
51  	struct rb_node node;
52  	struct elf_hash_node hash;
53  	struct elf_hash_node name_hash;
54  	GElf_Sym sym;
55  	struct section *sec;
56  	char *name;
57  	unsigned int idx, len;
58  	unsigned long offset;
59  	unsigned long __subtree_last;
60  	struct symbol *pfunc, *cfunc, *alias;
61  	unsigned char bind, type;
62  	u8 uaccess_safe      : 1;
63  	u8 static_call_tramp : 1;
64  	u8 retpoline_thunk   : 1;
65  	u8 return_thunk      : 1;
66  	u8 fentry            : 1;
67  	u8 profiling_func    : 1;
68  	u8 warned	     : 1;
69  	u8 embedded_insn     : 1;
70  	struct list_head pv_target;
71  	struct reloc *relocs;
72  };
73  
74  struct reloc {
75  	struct elf_hash_node hash;
76  	struct section *sec;
77  	struct symbol *sym;
78  	struct reloc *sym_next_reloc;
79  };
80  
81  struct elf {
82  	Elf *elf;
83  	GElf_Ehdr ehdr;
84  	int fd;
85  	bool changed;
86  	char *name;
87  	unsigned int num_files;
88  	struct list_head sections;
89  	unsigned long num_relocs;
90  
91  	int symbol_bits;
92  	int symbol_name_bits;
93  	int section_bits;
94  	int section_name_bits;
95  	int reloc_bits;
96  
97  	struct elf_hash_node **symbol_hash;
98  	struct elf_hash_node **symbol_name_hash;
99  	struct elf_hash_node **section_hash;
100  	struct elf_hash_node **section_name_hash;
101  	struct elf_hash_node **reloc_hash;
102  
103  	struct section *section_data;
104  	struct symbol *symbol_data;
105  };
106  
107  struct elf *elf_open_read(const char *name, int flags);
108  
109  struct section *elf_create_section(struct elf *elf, const char *name,
110  				   size_t entsize, unsigned int nr);
111  struct section *elf_create_section_pair(struct elf *elf, const char *name,
112  					size_t entsize, unsigned int nr,
113  					unsigned int reloc_nr);
114  
115  struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
116  
117  struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
118  				      unsigned long offset,
119  				      unsigned int reloc_idx,
120  				      struct section *insn_sec,
121  				      unsigned long insn_off);
122  
123  struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
124  				      unsigned long offset,
125  				      unsigned int reloc_idx,
126  				      struct symbol *sym,
127  				      s64 addend);
128  
129  int elf_write_insn(struct elf *elf, struct section *sec,
130  		   unsigned long offset, unsigned int len,
131  		   const char *insn);
132  int elf_write(struct elf *elf);
133  void elf_close(struct elf *elf);
134  
135  struct section *find_section_by_name(const struct elf *elf, const char *name);
136  struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
137  struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
138  struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
139  struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
140  int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
141  struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
142  struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
143  				     unsigned long offset, unsigned int len);
144  struct symbol *find_func_containing(struct section *sec, unsigned long offset);
145  
146  /*
147   * Try to see if it's a whole archive (vmlinux.o or module).
148   *
149   * Note this will miss the case where a module only has one source file.
150   */
has_multiple_files(struct elf * elf)151  static inline bool has_multiple_files(struct elf *elf)
152  {
153  	return elf->num_files > 1;
154  }
155  
elf_addr_size(struct elf * elf)156  static inline size_t elf_addr_size(struct elf *elf)
157  {
158  	return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
159  }
160  
elf_rela_size(struct elf * elf)161  static inline size_t elf_rela_size(struct elf *elf)
162  {
163  	return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
164  }
165  
elf_data_rela_type(struct elf * elf)166  static inline unsigned int elf_data_rela_type(struct elf *elf)
167  {
168  	return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
169  }
170  
elf_text_rela_type(struct elf * elf)171  static inline unsigned int elf_text_rela_type(struct elf *elf)
172  {
173  	return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
174  }
175  
is_reloc_sec(struct section * sec)176  static inline bool is_reloc_sec(struct section *sec)
177  {
178  	return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
179  }
180  
sec_changed(struct section * sec)181  static inline bool sec_changed(struct section *sec)
182  {
183  	return sec->_changed;
184  }
185  
mark_sec_changed(struct elf * elf,struct section * sec,bool changed)186  static inline void mark_sec_changed(struct elf *elf, struct section *sec,
187  				    bool changed)
188  {
189  	sec->_changed = changed;
190  	elf->changed |= changed;
191  }
192  
sec_num_entries(struct section * sec)193  static inline unsigned int sec_num_entries(struct section *sec)
194  {
195  	return sec->sh.sh_size / sec->sh.sh_entsize;
196  }
197  
reloc_idx(struct reloc * reloc)198  static inline unsigned int reloc_idx(struct reloc *reloc)
199  {
200  	return reloc - reloc->sec->relocs;
201  }
202  
reloc_rel(struct reloc * reloc)203  static inline void *reloc_rel(struct reloc *reloc)
204  {
205  	struct section *rsec = reloc->sec;
206  
207  	return rsec->data->d_buf + (reloc_idx(reloc) * rsec->sh.sh_entsize);
208  }
209  
is_32bit_reloc(struct reloc * reloc)210  static inline bool is_32bit_reloc(struct reloc *reloc)
211  {
212  	/*
213  	 * Elf32_Rel:   8 bytes
214  	 * Elf32_Rela: 12 bytes
215  	 * Elf64_Rel:  16 bytes
216  	 * Elf64_Rela: 24 bytes
217  	 */
218  	return reloc->sec->sh.sh_entsize < 16;
219  }
220  
221  #define __get_reloc_field(reloc, field)					\
222  ({									\
223  	is_32bit_reloc(reloc) ?						\
224  		((Elf32_Rela *)reloc_rel(reloc))->field :		\
225  		((Elf64_Rela *)reloc_rel(reloc))->field;		\
226  })
227  
228  #define __set_reloc_field(reloc, field, val)				\
229  ({									\
230  	if (is_32bit_reloc(reloc))					\
231  		((Elf32_Rela *)reloc_rel(reloc))->field = val;		\
232  	else								\
233  		((Elf64_Rela *)reloc_rel(reloc))->field = val;		\
234  })
235  
reloc_offset(struct reloc * reloc)236  static inline u64 reloc_offset(struct reloc *reloc)
237  {
238  	return __get_reloc_field(reloc, r_offset);
239  }
240  
set_reloc_offset(struct elf * elf,struct reloc * reloc,u64 offset)241  static inline void set_reloc_offset(struct elf *elf, struct reloc *reloc, u64 offset)
242  {
243  	__set_reloc_field(reloc, r_offset, offset);
244  	mark_sec_changed(elf, reloc->sec, true);
245  }
246  
reloc_addend(struct reloc * reloc)247  static inline s64 reloc_addend(struct reloc *reloc)
248  {
249  	return __get_reloc_field(reloc, r_addend);
250  }
251  
set_reloc_addend(struct elf * elf,struct reloc * reloc,s64 addend)252  static inline void set_reloc_addend(struct elf *elf, struct reloc *reloc, s64 addend)
253  {
254  	__set_reloc_field(reloc, r_addend, addend);
255  	mark_sec_changed(elf, reloc->sec, true);
256  }
257  
258  
reloc_sym(struct reloc * reloc)259  static inline unsigned int reloc_sym(struct reloc *reloc)
260  {
261  	u64 info = __get_reloc_field(reloc, r_info);
262  
263  	return is_32bit_reloc(reloc) ?
264  		ELF32_R_SYM(info) :
265  		ELF64_R_SYM(info);
266  }
267  
reloc_type(struct reloc * reloc)268  static inline unsigned int reloc_type(struct reloc *reloc)
269  {
270  	u64 info = __get_reloc_field(reloc, r_info);
271  
272  	return is_32bit_reloc(reloc) ?
273  		ELF32_R_TYPE(info) :
274  		ELF64_R_TYPE(info);
275  }
276  
set_reloc_sym(struct elf * elf,struct reloc * reloc,unsigned int sym)277  static inline void set_reloc_sym(struct elf *elf, struct reloc *reloc, unsigned int sym)
278  {
279  	u64 info = is_32bit_reloc(reloc) ?
280  		ELF32_R_INFO(sym, reloc_type(reloc)) :
281  		ELF64_R_INFO(sym, reloc_type(reloc));
282  
283  	__set_reloc_field(reloc, r_info, info);
284  
285  	mark_sec_changed(elf, reloc->sec, true);
286  }
set_reloc_type(struct elf * elf,struct reloc * reloc,unsigned int type)287  static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned int type)
288  {
289  	u64 info = is_32bit_reloc(reloc) ?
290  		ELF32_R_INFO(reloc_sym(reloc), type) :
291  		ELF64_R_INFO(reloc_sym(reloc), type);
292  
293  	__set_reloc_field(reloc, r_info, info);
294  
295  	mark_sec_changed(elf, reloc->sec, true);
296  }
297  
298  #define for_each_sec(file, sec)						\
299  	list_for_each_entry(sec, &file->elf->sections, list)
300  
301  #define sec_for_each_sym(sec, sym)					\
302  	list_for_each_entry(sym, &sec->symbol_list, list)
303  
304  #define for_each_sym(file, sym)						\
305  	for (struct section *__sec, *__fake = (struct section *)1;	\
306  	     __fake; __fake = NULL)					\
307  		for_each_sec(file, __sec)				\
308  			sec_for_each_sym(__sec, sym)
309  
310  #define for_each_reloc(rsec, reloc)					\
311  	for (int __i = 0, __fake = 1; __fake; __fake = 0)		\
312  		for (reloc = rsec->relocs;				\
313  		     __i < sec_num_entries(rsec);			\
314  		     __i++, reloc++)
315  
316  #define for_each_reloc_from(rsec, reloc)				\
317  	for (int __i = reloc_idx(reloc);				\
318  	     __i < sec_num_entries(rsec);				\
319  	     __i++, reloc++)
320  
321  #define OFFSET_STRIDE_BITS	4
322  #define OFFSET_STRIDE		(1UL << OFFSET_STRIDE_BITS)
323  #define OFFSET_STRIDE_MASK	(~(OFFSET_STRIDE - 1))
324  
325  #define for_offset_range(_offset, _start, _end)			\
326  	for (_offset = ((_start) & OFFSET_STRIDE_MASK);		\
327  	     _offset >= ((_start) & OFFSET_STRIDE_MASK) &&	\
328  	     _offset <= ((_end) & OFFSET_STRIDE_MASK);		\
329  	     _offset += OFFSET_STRIDE)
330  
sec_offset_hash(struct section * sec,unsigned long offset)331  static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
332  {
333  	u32 ol, oh, idx = sec->idx;
334  
335  	offset &= OFFSET_STRIDE_MASK;
336  
337  	ol = offset;
338  	oh = (offset >> 16) >> 16;
339  
340  	__jhash_mix(ol, oh, idx);
341  
342  	return ol;
343  }
344  
reloc_hash(struct reloc * reloc)345  static inline u32 reloc_hash(struct reloc *reloc)
346  {
347  	return sec_offset_hash(reloc->sec, reloc_offset(reloc));
348  }
349  
350  #endif /* _OBJTOOL_ELF_H */
351