1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
11 #include <linux/list.h>
12 #include <linux/hashtable.h>
13 #include <linux/rbtree.h>
14 #include <linux/jhash.h>
17 #ifdef LIBELF_USE_DEPRECATED
18 # define elf_getshdrnum elf_getshnum
19 # define elf_getshdrstrndx elf_getshstrndx
23 * Fallback for systems without this "read, mmaping if possible" cmd.
25 #ifndef ELF_C_READ_MMAP
26 #define ELF_C_READ_MMAP ELF_C_READ
30 struct list_head list
;
31 struct hlist_node hash
;
32 struct hlist_node name_hash
;
34 struct rb_root_cached symbol_tree
;
35 struct list_head symbol_list
;
36 struct section
*base
, *rsec
;
41 bool _changed
, text
, rodata
, noinstr
, init
, truncate
;
46 struct list_head list
;
48 struct hlist_node hash
;
49 struct hlist_node name_hash
;
53 unsigned int idx
, len
;
55 unsigned long __subtree_last
;
56 struct symbol
*pfunc
, *cfunc
, *alias
;
57 unsigned char bind
, type
;
59 u8 static_call_tramp
: 1;
60 u8 retpoline_thunk
: 1;
63 u8 profiling_func
: 1;
65 struct list_head pv_target
;
66 struct list_head reloc_list
;
70 struct hlist_node hash
;
77 struct list_head sym_reloc_entry
;
78 bool jump_table_start
;
87 unsigned int num_files
;
88 struct list_head sections
;
89 unsigned long num_relocs
;
94 int section_name_bits
;
97 struct hlist_head
*symbol_hash
;
98 struct hlist_head
*symbol_name_hash
;
99 struct hlist_head
*section_hash
;
100 struct hlist_head
*section_name_hash
;
101 struct hlist_head
*reloc_hash
;
103 struct section
*section_data
;
104 struct symbol
*symbol_data
;
107 struct elf
*elf_open_read(const char *name
, int flags
);
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
);
115 struct symbol
*elf_create_prefix_symbol(struct elf
*elf
, struct symbol
*orig
, long size
);
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
);
123 struct reloc
*elf_init_reloc_data_sym(struct elf
*elf
, struct section
*sec
,
124 unsigned long offset
,
125 unsigned int reloc_idx
,
129 int elf_write_insn(struct elf
*elf
, struct section
*sec
,
130 unsigned long offset
, unsigned int len
,
132 int elf_write_reloc(struct elf
*elf
, struct reloc
*reloc
);
133 int elf_write(struct elf
*elf
);
134 void elf_close(struct elf
*elf
);
136 struct section
*find_section_by_name(const struct elf
*elf
, const char *name
);
137 struct symbol
*find_func_by_offset(struct section
*sec
, unsigned long offset
);
138 struct symbol
*find_symbol_by_offset(struct section
*sec
, unsigned long offset
);
139 struct symbol
*find_symbol_by_name(const struct elf
*elf
, const char *name
);
140 struct symbol
*find_symbol_containing(const struct section
*sec
, unsigned long offset
);
141 int find_symbol_hole_containing(const struct section
*sec
, unsigned long offset
);
142 struct reloc
*find_reloc_by_dest(const struct elf
*elf
, struct section
*sec
, unsigned long offset
);
143 struct reloc
*find_reloc_by_dest_range(const struct elf
*elf
, struct section
*sec
,
144 unsigned long offset
, unsigned int len
);
145 struct symbol
*find_func_containing(struct section
*sec
, unsigned long offset
);
148 * Try to see if it's a whole archive (vmlinux.o or module).
150 * Note this will miss the case where a module only has one source file.
152 static inline bool has_multiple_files(struct elf
*elf
)
154 return elf
->num_files
> 1;
157 static inline size_t elf_addr_size(struct elf
*elf
)
159 return elf
->ehdr
.e_ident
[EI_CLASS
] == ELFCLASS32
? 4 : 8;
162 static inline size_t elf_rela_size(struct elf
*elf
)
164 return elf_addr_size(elf
) == 4 ? sizeof(Elf32_Rela
) : sizeof(Elf64_Rela
);
167 static inline unsigned int elf_data_rela_type(struct elf
*elf
)
169 return elf_addr_size(elf
) == 4 ? R_DATA32
: R_DATA64
;
172 static inline unsigned int elf_text_rela_type(struct elf
*elf
)
174 return elf_addr_size(elf
) == 4 ? R_TEXT32
: R_TEXT64
;
177 static inline bool is_reloc_sec(struct section
*sec
)
179 return sec
->sh
.sh_type
== SHT_RELA
|| sec
->sh
.sh_type
== SHT_REL
;
182 static inline bool sec_changed(struct section
*sec
)
184 return sec
->_changed
;
187 static inline void mark_sec_changed(struct elf
*elf
, struct section
*sec
,
190 sec
->_changed
= changed
;
191 elf
->changed
|= changed
;
194 static inline unsigned int sec_num_entries(struct section
*sec
)
196 return sec
->sh
.sh_size
/ sec
->sh
.sh_entsize
;
199 static inline unsigned int reloc_idx(struct reloc
*reloc
)
201 return reloc
- reloc
->sec
->relocs
;
204 static inline unsigned long reloc_offset(struct reloc
*reloc
)
206 return reloc
->rel
.r_offset
;
209 static inline unsigned int reloc_type(struct reloc
*reloc
)
211 return GELF_R_TYPE(reloc
->rel
.r_info
);
214 static inline void set_reloc_type(struct reloc
*reloc
, int type
)
216 reloc
->rel
.r_info
= GELF_R_INFO(GELF_R_SYM(reloc
->rel
.r_info
), type
);
219 static inline s64
reloc_addend(struct reloc
*reloc
)
221 return reloc
->rela
.r_addend
;
224 #define for_each_sec(file, sec) \
225 list_for_each_entry(sec, &file->elf->sections, list)
227 #define sec_for_each_sym(sec, sym) \
228 list_for_each_entry(sym, &sec->symbol_list, list)
230 #define for_each_sym(file, sym) \
231 for (struct section *__sec, *__fake = (struct section *)1; \
232 __fake; __fake = NULL) \
233 for_each_sec(file, __sec) \
234 sec_for_each_sym(__sec, sym)
236 #define for_each_reloc(rsec, reloc) \
237 for (int __i = 0, __fake = 1; __fake; __fake = 0) \
238 for (reloc = rsec->relocs; \
239 __i < sec_num_entries(rsec); \
242 #define for_each_reloc_from(rsec, reloc) \
243 for (int __i = reloc_idx(reloc); \
244 __i < sec_num_entries(rsec); \
247 #define OFFSET_STRIDE_BITS 4
248 #define OFFSET_STRIDE (1UL << OFFSET_STRIDE_BITS)
249 #define OFFSET_STRIDE_MASK (~(OFFSET_STRIDE - 1))
251 #define for_offset_range(_offset, _start, _end) \
252 for (_offset = ((_start) & OFFSET_STRIDE_MASK); \
253 _offset >= ((_start) & OFFSET_STRIDE_MASK) && \
254 _offset <= ((_end) & OFFSET_STRIDE_MASK); \
255 _offset += OFFSET_STRIDE)
257 static inline u32
sec_offset_hash(struct section
*sec
, unsigned long offset
)
259 u32 ol
, oh
, idx
= sec
->idx
;
261 offset
&= OFFSET_STRIDE_MASK
;
264 oh
= (offset
>> 16) >> 16;
266 __jhash_mix(ol
, oh
, idx
);
271 static inline u32
reloc_hash(struct reloc
*reloc
)
273 return sec_offset_hash(reloc
->sec
, reloc_offset(reloc
));
276 #endif /* _OBJTOOL_ELF_H */