xref: /linux/tools/objtool/include/objtool/elf.h (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce) !
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 	u8 local_label       : 1;
71 	u8 frame_pointer     : 1;
72 	u8 ignore	     : 1;
73 	struct list_head pv_target;
74 	struct reloc *relocs;
75 	struct section *group_sec;
76 };
77 
78 struct reloc {
79 	struct elf_hash_node hash;
80 	struct section *sec;
81 	struct symbol *sym;
82 	unsigned long _sym_next_reloc;
83 };
84 
85 struct elf {
86 	Elf *elf;
87 	GElf_Ehdr ehdr;
88 	int fd;
89 	bool changed;
90 	char *name;
91 	unsigned int num_files;
92 	struct list_head sections;
93 	unsigned long num_relocs;
94 
95 	int symbol_bits;
96 	int symbol_name_bits;
97 	int section_bits;
98 	int section_name_bits;
99 	int reloc_bits;
100 
101 	struct elf_hash_node **symbol_hash;
102 	struct elf_hash_node **symbol_name_hash;
103 	struct elf_hash_node **section_hash;
104 	struct elf_hash_node **section_name_hash;
105 	struct elf_hash_node **reloc_hash;
106 
107 	struct section *section_data;
108 	struct symbol *symbol_data;
109 };
110 
111 struct elf *elf_open_read(const char *name, int flags);
112 
113 struct section *elf_create_section(struct elf *elf, const char *name,
114 				   size_t entsize, unsigned int nr);
115 struct section *elf_create_section_pair(struct elf *elf, const char *name,
116 					size_t entsize, unsigned int nr,
117 					unsigned int reloc_nr);
118 
119 struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
120 
121 struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
122 				      unsigned long offset,
123 				      unsigned int reloc_idx,
124 				      struct section *insn_sec,
125 				      unsigned long insn_off);
126 
127 struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
128 				      unsigned long offset,
129 				      unsigned int reloc_idx,
130 				      struct symbol *sym,
131 				      s64 addend);
132 
133 int elf_write_insn(struct elf *elf, struct section *sec,
134 		   unsigned long offset, unsigned int len,
135 		   const char *insn);
136 int elf_write(struct elf *elf);
137 void elf_close(struct elf *elf);
138 
139 struct section *find_section_by_name(const struct elf *elf, const char *name);
140 struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
141 struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
142 struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
143 struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
144 int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
145 struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
146 struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
147 				     unsigned long offset, unsigned int len);
148 struct symbol *find_func_containing(struct section *sec, unsigned long offset);
149 
150 /*
151  * Try to see if it's a whole archive (vmlinux.o or module).
152  *
153  * Note this will miss the case where a module only has one source file.
154  */
has_multiple_files(struct elf * elf)155 static inline bool has_multiple_files(struct elf *elf)
156 {
157 	return elf->num_files > 1;
158 }
159 
elf_addr_size(struct elf * elf)160 static inline size_t elf_addr_size(struct elf *elf)
161 {
162 	return elf->ehdr.e_ident[EI_CLASS] == ELFCLASS32 ? 4 : 8;
163 }
164 
elf_rela_size(struct elf * elf)165 static inline size_t elf_rela_size(struct elf *elf)
166 {
167 	return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
168 }
169 
elf_data_rela_type(struct elf * elf)170 static inline unsigned int elf_data_rela_type(struct elf *elf)
171 {
172 	return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
173 }
174 
elf_text_rela_type(struct elf * elf)175 static inline unsigned int elf_text_rela_type(struct elf *elf)
176 {
177 	return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
178 }
179 
is_reloc_sec(struct section * sec)180 static inline bool is_reloc_sec(struct section *sec)
181 {
182 	return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
183 }
184 
sec_changed(struct section * sec)185 static inline bool sec_changed(struct section *sec)
186 {
187 	return sec->_changed;
188 }
189 
mark_sec_changed(struct elf * elf,struct section * sec,bool changed)190 static inline void mark_sec_changed(struct elf *elf, struct section *sec,
191 				    bool changed)
192 {
193 	sec->_changed = changed;
194 	elf->changed |= changed;
195 }
196 
sec_num_entries(struct section * sec)197 static inline unsigned int sec_num_entries(struct section *sec)
198 {
199 	return sec->sh.sh_size / sec->sh.sh_entsize;
200 }
201 
reloc_idx(struct reloc * reloc)202 static inline unsigned int reloc_idx(struct reloc *reloc)
203 {
204 	return reloc - reloc->sec->relocs;
205 }
206 
reloc_rel(struct reloc * reloc)207 static inline void *reloc_rel(struct reloc *reloc)
208 {
209 	struct section *rsec = reloc->sec;
210 
211 	return rsec->data->d_buf + (reloc_idx(reloc) * rsec->sh.sh_entsize);
212 }
213 
is_32bit_reloc(struct reloc * reloc)214 static inline bool is_32bit_reloc(struct reloc *reloc)
215 {
216 	/*
217 	 * Elf32_Rel:   8 bytes
218 	 * Elf32_Rela: 12 bytes
219 	 * Elf64_Rel:  16 bytes
220 	 * Elf64_Rela: 24 bytes
221 	 */
222 	return reloc->sec->sh.sh_entsize < 16;
223 }
224 
225 #define __get_reloc_field(reloc, field)					\
226 ({									\
227 	is_32bit_reloc(reloc) ?						\
228 		((Elf32_Rela *)reloc_rel(reloc))->field :		\
229 		((Elf64_Rela *)reloc_rel(reloc))->field;		\
230 })
231 
232 #define __set_reloc_field(reloc, field, val)				\
233 ({									\
234 	if (is_32bit_reloc(reloc))					\
235 		((Elf32_Rela *)reloc_rel(reloc))->field = val;		\
236 	else								\
237 		((Elf64_Rela *)reloc_rel(reloc))->field = val;		\
238 })
239 
reloc_offset(struct reloc * reloc)240 static inline u64 reloc_offset(struct reloc *reloc)
241 {
242 	return __get_reloc_field(reloc, r_offset);
243 }
244 
set_reloc_offset(struct elf * elf,struct reloc * reloc,u64 offset)245 static inline void set_reloc_offset(struct elf *elf, struct reloc *reloc, u64 offset)
246 {
247 	__set_reloc_field(reloc, r_offset, offset);
248 	mark_sec_changed(elf, reloc->sec, true);
249 }
250 
reloc_addend(struct reloc * reloc)251 static inline s64 reloc_addend(struct reloc *reloc)
252 {
253 	return __get_reloc_field(reloc, r_addend);
254 }
255 
set_reloc_addend(struct elf * elf,struct reloc * reloc,s64 addend)256 static inline void set_reloc_addend(struct elf *elf, struct reloc *reloc, s64 addend)
257 {
258 	__set_reloc_field(reloc, r_addend, addend);
259 	mark_sec_changed(elf, reloc->sec, true);
260 }
261 
262 
reloc_sym(struct reloc * reloc)263 static inline unsigned int reloc_sym(struct reloc *reloc)
264 {
265 	u64 info = __get_reloc_field(reloc, r_info);
266 
267 	return is_32bit_reloc(reloc) ?
268 		ELF32_R_SYM(info) :
269 		ELF64_R_SYM(info);
270 }
271 
reloc_type(struct reloc * reloc)272 static inline unsigned int reloc_type(struct reloc *reloc)
273 {
274 	u64 info = __get_reloc_field(reloc, r_info);
275 
276 	return is_32bit_reloc(reloc) ?
277 		ELF32_R_TYPE(info) :
278 		ELF64_R_TYPE(info);
279 }
280 
set_reloc_sym(struct elf * elf,struct reloc * reloc,unsigned int sym)281 static inline void set_reloc_sym(struct elf *elf, struct reloc *reloc, unsigned int sym)
282 {
283 	u64 info = is_32bit_reloc(reloc) ?
284 		ELF32_R_INFO(sym, reloc_type(reloc)) :
285 		ELF64_R_INFO(sym, reloc_type(reloc));
286 
287 	__set_reloc_field(reloc, r_info, info);
288 
289 	mark_sec_changed(elf, reloc->sec, true);
290 }
set_reloc_type(struct elf * elf,struct reloc * reloc,unsigned int type)291 static inline void set_reloc_type(struct elf *elf, struct reloc *reloc, unsigned int type)
292 {
293 	u64 info = is_32bit_reloc(reloc) ?
294 		ELF32_R_INFO(reloc_sym(reloc), type) :
295 		ELF64_R_INFO(reloc_sym(reloc), type);
296 
297 	__set_reloc_field(reloc, r_info, info);
298 
299 	mark_sec_changed(elf, reloc->sec, true);
300 }
301 
302 #define RELOC_JUMP_TABLE_BIT 1UL
303 
304 /* Does reloc mark the beginning of a jump table? */
is_jump_table(struct reloc * reloc)305 static inline bool is_jump_table(struct reloc *reloc)
306 {
307 	return reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
308 }
309 
set_jump_table(struct reloc * reloc)310 static inline void set_jump_table(struct reloc *reloc)
311 {
312 	reloc->_sym_next_reloc |= RELOC_JUMP_TABLE_BIT;
313 }
314 
sym_next_reloc(struct reloc * reloc)315 static inline struct reloc *sym_next_reloc(struct reloc *reloc)
316 {
317 	return (struct reloc *)(reloc->_sym_next_reloc & ~RELOC_JUMP_TABLE_BIT);
318 }
319 
set_sym_next_reloc(struct reloc * reloc,struct reloc * next)320 static inline void set_sym_next_reloc(struct reloc *reloc, struct reloc *next)
321 {
322 	unsigned long bit = reloc->_sym_next_reloc & RELOC_JUMP_TABLE_BIT;
323 
324 	reloc->_sym_next_reloc = (unsigned long)next | bit;
325 }
326 
327 #define for_each_sec(file, sec)						\
328 	list_for_each_entry(sec, &file->elf->sections, list)
329 
330 #define sec_for_each_sym(sec, sym)					\
331 	list_for_each_entry(sym, &sec->symbol_list, list)
332 
333 #define for_each_sym(file, sym)						\
334 	for (struct section *__sec, *__fake = (struct section *)1;	\
335 	     __fake; __fake = NULL)					\
336 		for_each_sec(file, __sec)				\
337 			sec_for_each_sym(__sec, sym)
338 
339 #define for_each_reloc(rsec, reloc)					\
340 	for (int __i = 0, __fake = 1; __fake; __fake = 0)		\
341 		for (reloc = rsec->relocs;				\
342 		     __i < sec_num_entries(rsec);			\
343 		     __i++, reloc++)
344 
345 #define for_each_reloc_from(rsec, reloc)				\
346 	for (int __i = reloc_idx(reloc);				\
347 	     __i < sec_num_entries(rsec);				\
348 	     __i++, reloc++)
349 
350 #define OFFSET_STRIDE_BITS	4
351 #define OFFSET_STRIDE		(1UL << OFFSET_STRIDE_BITS)
352 #define OFFSET_STRIDE_MASK	(~(OFFSET_STRIDE - 1))
353 
354 #define for_offset_range(_offset, _start, _end)			\
355 	for (_offset = ((_start) & OFFSET_STRIDE_MASK);		\
356 	     _offset >= ((_start) & OFFSET_STRIDE_MASK) &&	\
357 	     _offset <= ((_end) & OFFSET_STRIDE_MASK);		\
358 	     _offset += OFFSET_STRIDE)
359 
sec_offset_hash(struct section * sec,unsigned long offset)360 static inline u32 sec_offset_hash(struct section *sec, unsigned long offset)
361 {
362 	u32 ol, oh, idx = sec->idx;
363 
364 	offset &= OFFSET_STRIDE_MASK;
365 
366 	ol = offset;
367 	oh = (offset >> 16) >> 16;
368 
369 	__jhash_mix(ol, oh, idx);
370 
371 	return ol;
372 }
373 
reloc_hash(struct reloc * reloc)374 static inline u32 reloc_hash(struct reloc *reloc)
375 {
376 	return sec_offset_hash(reloc->sec, reloc_offset(reloc));
377 }
378 
379 #endif /* _OBJTOOL_ELF_H */
380