mirror of
https://github.com/torvalds/linux.git
synced 2024-11-13 23:51:39 +00:00
objtool: Add elf_create_section_pair()
When creating an annotation section, allocate the reloc section data at the beginning. This simplifies the data model a bit and also saves memory due to the removal of malloc() in elf_rebuild_reloc_section(). With allyesconfig + CONFIG_DEBUG_INFO: - Before: peak heap memory consumption: 53.49G - After: peak heap memory consumption: 49.02G Link: https://lore.kernel.org/r/048e908f3ede9b66c15e44672b6dda992b1dae3e.1685464332.git.jpoimboe@kernel.org Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
parent
ff4082730c
commit
6342a20efb
@ -1,10 +1,13 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
|
|
||||||
#ifndef _OBJTOOL_ARCH_ELF
|
#ifndef _OBJTOOL_ARCH_ELF
|
||||||
#define _OBJTOOL_ARCH_ELF
|
#define _OBJTOOL_ARCH_ELF
|
||||||
|
|
||||||
#define R_NONE R_PPC_NONE
|
#define R_NONE R_PPC_NONE
|
||||||
#define R_ABS64 R_PPC64_ADDR64
|
#define R_ABS64 R_PPC64_ADDR64
|
||||||
#define R_ABS32 R_PPC_ADDR32
|
#define R_ABS32 R_PPC_ADDR32
|
||||||
|
#define R_DATA32 R_PPC_REL32
|
||||||
|
#define R_DATA64 R_PPC64_REL64
|
||||||
|
#define R_TEXT32 R_PPC_REL32
|
||||||
|
#define R_TEXT64 R_PPC64_REL32
|
||||||
|
|
||||||
#endif /* _OBJTOOL_ARCH_ELF */
|
#endif /* _OBJTOOL_ARCH_ELF */
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
#ifndef _OBJTOOL_ARCH_ELF
|
#ifndef _OBJTOOL_ARCH_ELF
|
||||||
#define _OBJTOOL_ARCH_ELF
|
#define _OBJTOOL_ARCH_ELF
|
||||||
|
|
||||||
#define R_NONE R_X86_64_NONE
|
#define R_NONE R_X86_64_NONE
|
||||||
#define R_ABS64 R_X86_64_64
|
|
||||||
#define R_ABS32 R_X86_64_32
|
#define R_ABS32 R_X86_64_32
|
||||||
|
#define R_ABS64 R_X86_64_64
|
||||||
|
#define R_DATA32 R_X86_64_PC32
|
||||||
|
#define R_DATA64 R_X86_64_PC32
|
||||||
|
#define R_TEXT32 R_X86_64_PC32
|
||||||
|
#define R_TEXT64 R_X86_64_PC32
|
||||||
|
|
||||||
#endif /* _OBJTOOL_ARCH_ELF */
|
#endif /* _OBJTOOL_ARCH_ELF */
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include <arch/elf.h>
|
|
||||||
#include <objtool/builtin.h>
|
#include <objtool/builtin.h>
|
||||||
#include <objtool/cfi.h>
|
#include <objtool/cfi.h>
|
||||||
#include <objtool/arch.h>
|
#include <objtool/arch.h>
|
||||||
@ -656,8 +655,8 @@ reachable:
|
|||||||
|
|
||||||
static int create_static_call_sections(struct objtool_file *file)
|
static int create_static_call_sections(struct objtool_file *file)
|
||||||
{
|
{
|
||||||
struct section *sec;
|
|
||||||
struct static_call_site *site;
|
struct static_call_site *site;
|
||||||
|
struct section *sec;
|
||||||
struct instruction *insn;
|
struct instruction *insn;
|
||||||
struct symbol *key_sym;
|
struct symbol *key_sym;
|
||||||
char *key_name, *tmp;
|
char *key_name, *tmp;
|
||||||
@ -677,24 +676,20 @@ static int create_static_call_sections(struct objtool_file *file)
|
|||||||
list_for_each_entry(insn, &file->static_call_list, call_node)
|
list_for_each_entry(insn, &file->static_call_list, call_node)
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".static_call_sites",
|
sec = elf_create_section_pair(file->elf, ".static_call_sites",
|
||||||
sizeof(struct static_call_site), idx);
|
sizeof(*site), idx, idx * 2);
|
||||||
if (!sec)
|
if (!sec)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* Allow modules to set the low bits of static_call_site::key */
|
/* Allow modules to modify the low bits of static_call_site::key */
|
||||||
sec->sh.sh_flags |= SHF_WRITE;
|
sec->sh.sh_flags |= SHF_WRITE;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->static_call_list, call_node) {
|
list_for_each_entry(insn, &file->static_call_list, call_node) {
|
||||||
|
|
||||||
site = (struct static_call_site *)sec->data->d_buf + idx;
|
|
||||||
memset(site, 0, sizeof(struct static_call_site));
|
|
||||||
|
|
||||||
/* populate reloc for 'addr' */
|
/* populate reloc for 'addr' */
|
||||||
if (elf_add_reloc_to_insn(file->elf, sec,
|
if (!elf_init_reloc_text_sym(file->elf, sec,
|
||||||
idx * sizeof(struct static_call_site),
|
idx * sizeof(*site), idx * 2,
|
||||||
R_X86_64_PC32,
|
|
||||||
insn->sec, insn->offset))
|
insn->sec, insn->offset))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -735,9 +730,9 @@ static int create_static_call_sections(struct objtool_file *file)
|
|||||||
free(key_name);
|
free(key_name);
|
||||||
|
|
||||||
/* populate reloc for 'key' */
|
/* populate reloc for 'key' */
|
||||||
if (elf_add_reloc(file->elf, sec,
|
if (!elf_init_reloc_data_sym(file->elf, sec,
|
||||||
idx * sizeof(struct static_call_site) + 4,
|
idx * sizeof(*site) + 4,
|
||||||
R_X86_64_PC32, key_sym,
|
(idx * 2) + 1, key_sym,
|
||||||
is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
|
is_sibling_call(insn) * STATIC_CALL_SITE_TAIL))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -766,26 +761,18 @@ static int create_retpoline_sites_sections(struct objtool_file *file)
|
|||||||
if (!idx)
|
if (!idx)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".retpoline_sites",
|
sec = elf_create_section_pair(file->elf, ".retpoline_sites",
|
||||||
sizeof(int), idx);
|
sizeof(int), idx, idx);
|
||||||
if (!sec) {
|
if (!sec)
|
||||||
WARN("elf_create_section: .retpoline_sites");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->retpoline_call_list, call_node) {
|
list_for_each_entry(insn, &file->retpoline_call_list, call_node) {
|
||||||
|
|
||||||
int *site = (int *)sec->data->d_buf + idx;
|
if (!elf_init_reloc_text_sym(file->elf, sec,
|
||||||
*site = 0;
|
idx * sizeof(int), idx,
|
||||||
|
insn->sec, insn->offset))
|
||||||
if (elf_add_reloc_to_insn(file->elf, sec,
|
|
||||||
idx * sizeof(int),
|
|
||||||
R_X86_64_PC32,
|
|
||||||
insn->sec, insn->offset)) {
|
|
||||||
WARN("elf_add_reloc_to_insn: .retpoline_sites");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@ -812,26 +799,18 @@ static int create_return_sites_sections(struct objtool_file *file)
|
|||||||
if (!idx)
|
if (!idx)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".return_sites",
|
sec = elf_create_section_pair(file->elf, ".return_sites",
|
||||||
sizeof(int), idx);
|
sizeof(int), idx, idx);
|
||||||
if (!sec) {
|
if (!sec)
|
||||||
WARN("elf_create_section: .return_sites");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->return_thunk_list, call_node) {
|
list_for_each_entry(insn, &file->return_thunk_list, call_node) {
|
||||||
|
|
||||||
int *site = (int *)sec->data->d_buf + idx;
|
if (!elf_init_reloc_text_sym(file->elf, sec,
|
||||||
*site = 0;
|
idx * sizeof(int), idx,
|
||||||
|
insn->sec, insn->offset))
|
||||||
if (elf_add_reloc_to_insn(file->elf, sec,
|
|
||||||
idx * sizeof(int),
|
|
||||||
R_X86_64_PC32,
|
|
||||||
insn->sec, insn->offset)) {
|
|
||||||
WARN("elf_add_reloc_to_insn: .return_sites");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@ -864,12 +843,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
|
|||||||
if (!idx)
|
if (!idx)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".ibt_endbr_seal",
|
sec = elf_create_section_pair(file->elf, ".ibt_endbr_seal",
|
||||||
sizeof(int), idx);
|
sizeof(int), idx, idx);
|
||||||
if (!sec) {
|
if (!sec)
|
||||||
WARN("elf_create_section: .ibt_endbr_seal");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->endbr_list, call_node) {
|
list_for_each_entry(insn, &file->endbr_list, call_node) {
|
||||||
@ -884,13 +861,10 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file)
|
|||||||
!strcmp(sym->name, "cleanup_module")))
|
!strcmp(sym->name, "cleanup_module")))
|
||||||
WARN("%s(): not an indirect call target", sym->name);
|
WARN("%s(): not an indirect call target", sym->name);
|
||||||
|
|
||||||
if (elf_add_reloc_to_insn(file->elf, sec,
|
if (!elf_init_reloc_text_sym(file->elf, sec,
|
||||||
idx * sizeof(int),
|
idx * sizeof(int), idx,
|
||||||
R_X86_64_PC32,
|
insn->sec, insn->offset))
|
||||||
insn->sec, insn->offset)) {
|
|
||||||
WARN("elf_add_reloc_to_insn: .ibt_endbr_seal");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
@ -902,7 +876,6 @@ static int create_cfi_sections(struct objtool_file *file)
|
|||||||
{
|
{
|
||||||
struct section *sec;
|
struct section *sec;
|
||||||
struct symbol *sym;
|
struct symbol *sym;
|
||||||
unsigned int *loc;
|
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
sec = find_section_by_name(file->elf, ".cfi_sites");
|
sec = find_section_by_name(file->elf, ".cfi_sites");
|
||||||
@ -923,7 +896,8 @@ static int create_cfi_sections(struct objtool_file *file)
|
|||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".cfi_sites", sizeof(unsigned int), idx);
|
sec = elf_create_section_pair(file->elf, ".cfi_sites",
|
||||||
|
sizeof(unsigned int), idx, idx);
|
||||||
if (!sec)
|
if (!sec)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -935,12 +909,8 @@ static int create_cfi_sections(struct objtool_file *file)
|
|||||||
if (strncmp(sym->name, "__cfi_", 6))
|
if (strncmp(sym->name, "__cfi_", 6))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
loc = (unsigned int *)sec->data->d_buf + idx;
|
if (!elf_init_reloc_text_sym(file->elf, sec,
|
||||||
memset(loc, 0, sizeof(unsigned int));
|
idx * sizeof(unsigned int), idx,
|
||||||
|
|
||||||
if (elf_add_reloc_to_insn(file->elf, sec,
|
|
||||||
idx * sizeof(unsigned int),
|
|
||||||
R_X86_64_PC32,
|
|
||||||
sym->sec, sym->offset))
|
sym->sec, sym->offset))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -971,7 +941,8 @@ static int create_mcount_loc_sections(struct objtool_file *file)
|
|||||||
list_for_each_entry(insn, &file->mcount_loc_list, call_node)
|
list_for_each_entry(insn, &file->mcount_loc_list, call_node)
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx);
|
sec = elf_create_section_pair(file->elf, "__mcount_loc", addr_size,
|
||||||
|
idx, idx);
|
||||||
if (!sec)
|
if (!sec)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -979,17 +950,17 @@ static int create_mcount_loc_sections(struct objtool_file *file)
|
|||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->mcount_loc_list, call_node) {
|
list_for_each_entry(insn, &file->mcount_loc_list, call_node) {
|
||||||
void *loc;
|
|
||||||
|
|
||||||
loc = sec->data->d_buf + idx;
|
struct reloc *reloc;
|
||||||
memset(loc, 0, addr_size);
|
|
||||||
|
|
||||||
if (elf_add_reloc_to_insn(file->elf, sec, idx,
|
reloc = elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx,
|
||||||
addr_size == sizeof(u64) ? R_ABS64 : R_ABS32,
|
insn->sec, insn->offset);
|
||||||
insn->sec, insn->offset))
|
if (!reloc)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
idx += addr_size;
|
reloc->type = addr_size == 8 ? R_ABS64 : R_ABS32;
|
||||||
|
|
||||||
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -999,7 +970,6 @@ static int create_direct_call_sections(struct objtool_file *file)
|
|||||||
{
|
{
|
||||||
struct instruction *insn;
|
struct instruction *insn;
|
||||||
struct section *sec;
|
struct section *sec;
|
||||||
unsigned int *loc;
|
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
sec = find_section_by_name(file->elf, ".call_sites");
|
sec = find_section_by_name(file->elf, ".call_sites");
|
||||||
@ -1016,19 +986,16 @@ static int create_direct_call_sections(struct objtool_file *file)
|
|||||||
list_for_each_entry(insn, &file->call_list, call_node)
|
list_for_each_entry(insn, &file->call_list, call_node)
|
||||||
idx++;
|
idx++;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".call_sites", sizeof(unsigned int), idx);
|
sec = elf_create_section_pair(file->elf, ".call_sites",
|
||||||
|
sizeof(unsigned int), idx, idx);
|
||||||
if (!sec)
|
if (!sec)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(insn, &file->call_list, call_node) {
|
list_for_each_entry(insn, &file->call_list, call_node) {
|
||||||
|
|
||||||
loc = (unsigned int *)sec->data->d_buf + idx;
|
if (!elf_init_reloc_text_sym(file->elf, sec,
|
||||||
memset(loc, 0, sizeof(unsigned int));
|
idx * sizeof(unsigned int), idx,
|
||||||
|
|
||||||
if (elf_add_reloc_to_insn(file->elf, sec,
|
|
||||||
idx * sizeof(unsigned int),
|
|
||||||
R_X86_64_PC32,
|
|
||||||
insn->sec, insn->offset))
|
insn->sec, insn->offset))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -533,41 +533,6 @@ err:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct section *elf_create_rela_section(struct elf *elf,
|
|
||||||
struct section *sec);
|
|
||||||
|
|
||||||
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
|
|
||||||
unsigned int type, struct symbol *sym, s64 addend)
|
|
||||||
{
|
|
||||||
struct reloc *reloc;
|
|
||||||
|
|
||||||
if (!sec->rsec && !elf_create_rela_section(elf, sec))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
reloc = malloc(sizeof(*reloc));
|
|
||||||
if (!reloc) {
|
|
||||||
perror("malloc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
memset(reloc, 0, sizeof(*reloc));
|
|
||||||
|
|
||||||
reloc->sec = sec->rsec;
|
|
||||||
reloc->offset = offset;
|
|
||||||
reloc->type = type;
|
|
||||||
reloc->sym = sym;
|
|
||||||
reloc->addend = addend;
|
|
||||||
|
|
||||||
list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
|
|
||||||
list_add_tail(&reloc->list, &sec->rsec->reloc_list);
|
|
||||||
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
|
|
||||||
|
|
||||||
sec->rsec->sh.sh_size += sec->rsec->sh.sh_entsize;
|
|
||||||
|
|
||||||
mark_sec_changed(elf, sec->rsec, true);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure that any reloc section containing references to @sym is marked
|
* Ensure that any reloc section containing references to @sym is marked
|
||||||
* changed such that it will get re-generated in elf_rebuild_reloc_sections()
|
* changed such that it will get re-generated in elf_rebuild_reloc_sections()
|
||||||
@ -841,13 +806,57 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size)
|
|||||||
return sym;
|
return sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
|
static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec,
|
||||||
unsigned long offset, unsigned int type,
|
unsigned int reloc_idx,
|
||||||
struct section *insn_sec, unsigned long insn_off)
|
unsigned long offset, struct symbol *sym,
|
||||||
|
s64 addend, unsigned int type)
|
||||||
|
{
|
||||||
|
struct reloc *reloc;
|
||||||
|
|
||||||
|
if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) {
|
||||||
|
WARN("%s: bad reloc_idx %u for %s with size 0x%lx",
|
||||||
|
__func__, reloc_idx, rsec->name, rsec->sh.sh_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
reloc = malloc(sizeof(*reloc));
|
||||||
|
if (!reloc) {
|
||||||
|
perror("malloc");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
memset(reloc, 0, sizeof(*reloc));
|
||||||
|
|
||||||
|
reloc->idx = reloc_idx;
|
||||||
|
reloc->sec = rsec;
|
||||||
|
reloc->offset = offset;
|
||||||
|
reloc->type = type;
|
||||||
|
reloc->sym = sym;
|
||||||
|
reloc->addend = addend;
|
||||||
|
|
||||||
|
list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list);
|
||||||
|
list_add_tail(&reloc->list, &rsec->reloc_list);
|
||||||
|
elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc));
|
||||||
|
|
||||||
|
mark_sec_changed(elf, rsec, true);
|
||||||
|
|
||||||
|
return reloc;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
|
||||||
|
unsigned long offset,
|
||||||
|
unsigned int reloc_idx,
|
||||||
|
struct section *insn_sec,
|
||||||
|
unsigned long insn_off)
|
||||||
{
|
{
|
||||||
struct symbol *sym = insn_sec->sym;
|
struct symbol *sym = insn_sec->sym;
|
||||||
int addend = insn_off;
|
int addend = insn_off;
|
||||||
|
|
||||||
|
if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) {
|
||||||
|
WARN("bad call to %s() for data symbol %s",
|
||||||
|
__func__, sym->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!sym) {
|
if (!sym) {
|
||||||
/*
|
/*
|
||||||
* Due to how weak functions work, we must use section based
|
* Due to how weak functions work, we must use section based
|
||||||
@ -857,12 +866,29 @@ int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
|
|||||||
*/
|
*/
|
||||||
sym = elf_create_section_symbol(elf, insn_sec);
|
sym = elf_create_section_symbol(elf, insn_sec);
|
||||||
if (!sym)
|
if (!sym)
|
||||||
return -1;
|
return NULL;
|
||||||
|
|
||||||
insn_sec->sym = sym;
|
insn_sec->sym = sym;
|
||||||
}
|
}
|
||||||
|
|
||||||
return elf_add_reloc(elf, sec, offset, type, sym, addend);
|
return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
|
||||||
|
elf_text_rela_type(elf));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
|
||||||
|
unsigned long offset,
|
||||||
|
unsigned int reloc_idx,
|
||||||
|
struct symbol *sym,
|
||||||
|
s64 addend)
|
||||||
|
{
|
||||||
|
if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) {
|
||||||
|
WARN("bad call to %s() for text symbol %s",
|
||||||
|
__func__, sym->name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend,
|
||||||
|
elf_data_rela_type(elf));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
|
static int read_reloc(struct section *rsec, int i, struct reloc *reloc)
|
||||||
@ -1048,7 +1074,7 @@ static int elf_add_string(struct elf *elf, struct section *strtab, char *str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct section *elf_create_section(struct elf *elf, const char *name,
|
struct section *elf_create_section(struct elf *elf, const char *name,
|
||||||
size_t entsize, int nr)
|
size_t entsize, unsigned int nr)
|
||||||
{
|
{
|
||||||
struct section *sec, *shstrtab;
|
struct section *sec, *shstrtab;
|
||||||
size_t size = entsize * nr;
|
size_t size = entsize * nr;
|
||||||
@ -1129,7 +1155,8 @@ struct section *elf_create_section(struct elf *elf, const char *name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct section *elf_create_rela_section(struct elf *elf,
|
static struct section *elf_create_rela_section(struct elf *elf,
|
||||||
struct section *sec)
|
struct section *sec,
|
||||||
|
unsigned int reloc_nr)
|
||||||
{
|
{
|
||||||
struct section *rsec;
|
struct section *rsec;
|
||||||
char *rsec_name;
|
char *rsec_name;
|
||||||
@ -1142,46 +1169,50 @@ static struct section *elf_create_rela_section(struct elf *elf,
|
|||||||
strcpy(rsec_name, ".rela");
|
strcpy(rsec_name, ".rela");
|
||||||
strcat(rsec_name, sec->name);
|
strcat(rsec_name, sec->name);
|
||||||
|
|
||||||
rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0);
|
rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr);
|
||||||
free(rsec_name);
|
free(rsec_name);
|
||||||
if (!rsec)
|
if (!rsec)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
sec->rsec = rsec;
|
rsec->data->d_type = ELF_T_RELA;
|
||||||
rsec->base = sec;
|
|
||||||
|
|
||||||
rsec->sh.sh_type = SHT_RELA;
|
rsec->sh.sh_type = SHT_RELA;
|
||||||
rsec->sh.sh_addralign = elf_addr_size(elf);
|
rsec->sh.sh_addralign = elf_addr_size(elf);
|
||||||
rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
|
rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx;
|
||||||
rsec->sh.sh_info = sec->idx;
|
rsec->sh.sh_info = sec->idx;
|
||||||
rsec->sh.sh_flags = SHF_INFO_LINK;
|
rsec->sh.sh_flags = SHF_INFO_LINK;
|
||||||
|
|
||||||
|
sec->rsec = rsec;
|
||||||
|
rsec->base = sec;
|
||||||
|
|
||||||
return rsec;
|
return rsec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct section *elf_create_section_pair(struct elf *elf, const char *name,
|
||||||
|
size_t entsize, unsigned int nr,
|
||||||
|
unsigned int reloc_nr)
|
||||||
|
{
|
||||||
|
struct section *sec;
|
||||||
|
|
||||||
|
sec = elf_create_section(elf, name, entsize, nr);
|
||||||
|
if (!sec)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!elf_create_rela_section(elf, sec, reloc_nr))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return sec;
|
||||||
|
}
|
||||||
|
|
||||||
static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
|
static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec)
|
||||||
{
|
{
|
||||||
bool rela = rsec->sh.sh_type == SHT_RELA;
|
|
||||||
struct reloc *reloc;
|
struct reloc *reloc;
|
||||||
int idx = 0, ret;
|
int idx = 0, ret;
|
||||||
void *buf;
|
|
||||||
|
|
||||||
/* Allocate a buffer for relocations */
|
|
||||||
buf = malloc(rsec->sh.sh_size);
|
|
||||||
if (!buf) {
|
|
||||||
perror("malloc");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rsec->data->d_buf = buf;
|
|
||||||
rsec->data->d_size = rsec->sh.sh_size;
|
|
||||||
rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL;
|
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
list_for_each_entry(reloc, &rsec->reloc_list, list) {
|
list_for_each_entry(reloc, &rsec->reloc_list, list) {
|
||||||
reloc->rel.r_offset = reloc->offset;
|
reloc->rel.r_offset = reloc->offset;
|
||||||
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
|
reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type);
|
||||||
if (rela) {
|
if (rsec->sh.sh_type == SHT_RELA) {
|
||||||
reloc->rela.r_addend = reloc->addend;
|
reloc->rela.r_addend = reloc->addend;
|
||||||
ret = gelf_update_rela(rsec->data, idx, &reloc->rela);
|
ret = gelf_update_rela(rsec->data, idx, &reloc->rela);
|
||||||
} else {
|
} else {
|
||||||
|
@ -111,15 +111,26 @@ struct elf {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct elf *elf_open_read(const char *name, int flags);
|
struct elf *elf_open_read(const char *name, int flags);
|
||||||
struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr);
|
|
||||||
|
struct section *elf_create_section(struct elf *elf, const char *name,
|
||||||
|
size_t entsize, unsigned int nr);
|
||||||
|
struct section *elf_create_section_pair(struct elf *elf, const char *name,
|
||||||
|
size_t entsize, unsigned int nr,
|
||||||
|
unsigned int reloc_nr);
|
||||||
|
|
||||||
struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
|
struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size);
|
||||||
|
|
||||||
int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset,
|
struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec,
|
||||||
unsigned int type, struct symbol *sym, s64 addend);
|
unsigned long offset,
|
||||||
int elf_add_reloc_to_insn(struct elf *elf, struct section *sec,
|
unsigned int reloc_idx,
|
||||||
unsigned long offset, unsigned int type,
|
struct section *insn_sec,
|
||||||
struct section *insn_sec, unsigned long insn_off);
|
unsigned long insn_off);
|
||||||
|
|
||||||
|
struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec,
|
||||||
|
unsigned long offset,
|
||||||
|
unsigned int reloc_idx,
|
||||||
|
struct symbol *sym,
|
||||||
|
s64 addend);
|
||||||
|
|
||||||
int elf_write_insn(struct elf *elf, struct section *sec,
|
int elf_write_insn(struct elf *elf, struct section *sec,
|
||||||
unsigned long offset, unsigned int len,
|
unsigned long offset, unsigned int len,
|
||||||
@ -159,6 +170,16 @@ static inline size_t elf_rela_size(struct elf *elf)
|
|||||||
return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
|
return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline unsigned int elf_data_rela_type(struct elf *elf)
|
||||||
|
{
|
||||||
|
return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int elf_text_rela_type(struct elf *elf)
|
||||||
|
{
|
||||||
|
return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool is_reloc_sec(struct section *sec)
|
static inline bool is_reloc_sec(struct section *sec)
|
||||||
{
|
{
|
||||||
return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
|
return sec->sh.sh_type == SHT_RELA || sec->sh.sh_type == SHT_REL;
|
||||||
|
@ -118,7 +118,7 @@ static int write_orc_entry(struct elf *elf, struct section *orc_sec,
|
|||||||
orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
|
orc->bp_offset = bswap_if_needed(elf, orc->bp_offset);
|
||||||
|
|
||||||
/* populate reloc for ip */
|
/* populate reloc for ip */
|
||||||
if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32,
|
if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx,
|
||||||
insn_sec, insn_off))
|
insn_sec, insn_off))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -242,7 +242,7 @@ int orc_create(struct objtool_file *file)
|
|||||||
if (!orc_sec)
|
if (!orc_sec)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), nr);
|
sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr);
|
||||||
if (!sec)
|
if (!sec)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user