mirror of https://github.com/dynup/kpatch
kpatch-build: do symbol/section bundling in create-diff-object
kpatch-elf.c is used by binaries other than create-diff-object, but create-diff-object is the only one that cares about "bundling". Move the bundling to create-diff-object. Fixes #700. Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
This commit is contained in:
parent
5888f316e6
commit
b72027c44e
|
@ -81,6 +81,102 @@ struct special_section {
|
||||||
* Functions
|
* Functions
|
||||||
* **********/
|
* **********/
|
||||||
|
|
||||||
|
static int is_bundleable(struct symbol *sym)
|
||||||
|
{
|
||||||
|
if (sym->type == STT_FUNC &&
|
||||||
|
!strncmp(sym->sec->name, ".text.",6) &&
|
||||||
|
!strcmp(sym->sec->name + 6, sym->name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (sym->type == STT_FUNC &&
|
||||||
|
!strncmp(sym->sec->name, ".text.unlikely.",15) &&
|
||||||
|
!strcmp(sym->sec->name + 15, sym->name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (sym->type == STT_OBJECT &&
|
||||||
|
!strncmp(sym->sec->name, ".data.",6) &&
|
||||||
|
!strcmp(sym->sec->name + 6, sym->name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (sym->type == STT_OBJECT &&
|
||||||
|
!strncmp(sym->sec->name, ".rodata.",8) &&
|
||||||
|
!strcmp(sym->sec->name + 8, sym->name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (sym->type == STT_OBJECT &&
|
||||||
|
!strncmp(sym->sec->name, ".bss.",5) &&
|
||||||
|
!strcmp(sym->sec->name + 5, sym->name))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __powerpc__
|
||||||
|
/* Symbol st_others value for powerpc */
|
||||||
|
#define STO_PPC64_LOCAL_BIT 5
|
||||||
|
#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
|
||||||
|
#define PPC64_LOCAL_ENTRY_OFFSET(other) \
|
||||||
|
(((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On ppc64le, the function prologue generated by GCC 6+ has the sequence:
|
||||||
|
*
|
||||||
|
* .globl my_func
|
||||||
|
* .type my_func, @function
|
||||||
|
* .quad .TOC.-my_func
|
||||||
|
* my_func:
|
||||||
|
* .reloc ., R_PPC64_ENTRY ; optional
|
||||||
|
* ld r2,-8(r12)
|
||||||
|
* add r2,r2,r12
|
||||||
|
* .localentry my_func, .-my_func
|
||||||
|
*
|
||||||
|
* my_func is the global entry point, which, when called, sets up the TOC.
|
||||||
|
* .localentry is the local entry point, for calls to the function from within
|
||||||
|
* the object file. The local entry point is 8 bytes after the global entry
|
||||||
|
* point.
|
||||||
|
*/
|
||||||
|
static int is_localentry_sym(struct symbol *sym)
|
||||||
|
{
|
||||||
|
if (sym->type != STT_FUNC || sym->sym.st_shndx == SHN_UNDEF)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (sym->sym.st_value != 0x8)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static int is_localentry_sym(struct symbol *sym)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When compiling with -ffunction-sections and -fdata-sections, almost every
|
||||||
|
* symbol gets its own dedicated section. We call such symbols "bundled"
|
||||||
|
* symbols. They're indicated by "sym->sec->sym == sym".
|
||||||
|
*/
|
||||||
|
static void kpatch_bundle_symbols(struct kpatch_elf *kelf)
|
||||||
|
{
|
||||||
|
struct symbol *sym;
|
||||||
|
|
||||||
|
list_for_each_entry(sym, &kelf->symbols, list) {
|
||||||
|
if (is_bundleable(sym)) {
|
||||||
|
if (sym->sym.st_value != 0 && !is_localentry_sym(sym)) {
|
||||||
|
ERROR("symbol %s at offset %lu within section %s, expected 0",
|
||||||
|
sym->name, sym->sym.st_value,
|
||||||
|
sym->sec->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
sym->sec->sym = sym;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function detects whether the given symbol is a "special" static local
|
* This function detects whether the given symbol is a "special" static local
|
||||||
* variable (for lack of a better term).
|
* variable (for lack of a better term).
|
||||||
|
@ -2713,6 +2809,9 @@ int main(int argc, char *argv[])
|
||||||
kelf_base = kpatch_elf_open(arguments.args[0]);
|
kelf_base = kpatch_elf_open(arguments.args[0]);
|
||||||
kelf_patched = kpatch_elf_open(arguments.args[1]);
|
kelf_patched = kpatch_elf_open(arguments.args[1]);
|
||||||
|
|
||||||
|
kpatch_bundle_symbols(kelf_base);
|
||||||
|
kpatch_bundle_symbols(kelf_patched);
|
||||||
|
|
||||||
kpatch_compare_elf_headers(kelf_base->elf, kelf_patched->elf);
|
kpatch_compare_elf_headers(kelf_base->elf, kelf_patched->elf);
|
||||||
kpatch_check_program_headers(kelf_base->elf);
|
kpatch_check_program_headers(kelf_base->elf);
|
||||||
kpatch_check_program_headers(kelf_patched->elf);
|
kpatch_check_program_headers(kelf_patched->elf);
|
||||||
|
|
|
@ -76,46 +76,6 @@ int is_debug_section(struct section *sec)
|
||||||
!strncmp(name, ".eh_frame", 9);
|
!strncmp(name, ".eh_frame", 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __powerpc__
|
|
||||||
|
|
||||||
/* Symbol st_others value for powerpc */
|
|
||||||
#define STO_PPC64_LOCAL_BIT 5
|
|
||||||
#define STO_PPC64_LOCAL_MASK (7 << STO_PPC64_LOCAL_BIT)
|
|
||||||
#define PPC64_LOCAL_ENTRY_OFFSET(other) \
|
|
||||||
(((1 << (((other) & STO_PPC64_LOCAL_MASK) >> STO_PPC64_LOCAL_BIT)) >> 2) << 2)
|
|
||||||
|
|
||||||
/*
|
|
||||||
* On ppc64le, the function prologue generated by GCC 6+ has the sequence:
|
|
||||||
*
|
|
||||||
* .globl my_func
|
|
||||||
* .type my_func, @function
|
|
||||||
* .quad .TOC.-my_func
|
|
||||||
* my_func:
|
|
||||||
* .reloc ., R_PPC64_ENTRY ; optional
|
|
||||||
* ld r2,-8(r12)
|
|
||||||
* add r2,r2,r12
|
|
||||||
* .localentry my_func, .-my_func
|
|
||||||
*
|
|
||||||
* my_func is the global entry point, which, when called, sets up the TOC.
|
|
||||||
* .localentry is the local entry point, for calls to the function from within
|
|
||||||
* the object file. The local entry point is 8 bytes after the global entry
|
|
||||||
* point.
|
|
||||||
*/
|
|
||||||
static int is_localentry_sym(struct symbol *sym)
|
|
||||||
{
|
|
||||||
if (sym->type != STT_FUNC || sym->sym.st_shndx == SHN_UNDEF)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (sym->sym.st_value != 0x8)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!PPC64_LOCAL_ENTRY_OFFSET(sym->sym.st_other))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct section *find_section_by_index(struct list_head *list, unsigned int index)
|
struct section *find_section_by_index(struct list_head *list, unsigned int index)
|
||||||
{
|
{
|
||||||
struct section *sec;
|
struct section *sec;
|
||||||
|
@ -299,36 +259,6 @@ void kpatch_create_section_list(struct kpatch_elf *kelf)
|
||||||
ERROR("expected NULL");
|
ERROR("expected NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_bundleable(struct symbol *sym)
|
|
||||||
{
|
|
||||||
if (sym->type == STT_FUNC &&
|
|
||||||
!strncmp(sym->sec->name, ".text.",6) &&
|
|
||||||
!strcmp(sym->sec->name + 6, sym->name))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (sym->type == STT_FUNC &&
|
|
||||||
!strncmp(sym->sec->name, ".text.unlikely.",15) &&
|
|
||||||
!strcmp(sym->sec->name + 15, sym->name))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (sym->type == STT_OBJECT &&
|
|
||||||
!strncmp(sym->sec->name, ".data.",6) &&
|
|
||||||
!strcmp(sym->sec->name + 6, sym->name))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (sym->type == STT_OBJECT &&
|
|
||||||
!strncmp(sym->sec->name, ".rodata.",8) &&
|
|
||||||
!strcmp(sym->sec->name + 8, sym->name))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
if (sym->type == STT_OBJECT &&
|
|
||||||
!strncmp(sym->sec->name, ".bss.",5) &&
|
|
||||||
!strcmp(sym->sec->name + 5, sym->name))
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void kpatch_create_symbol_list(struct kpatch_elf *kelf)
|
void kpatch_create_symbol_list(struct kpatch_elf *kelf)
|
||||||
{
|
{
|
||||||
struct section *symtab;
|
struct section *symtab;
|
||||||
|
@ -367,18 +297,7 @@ void kpatch_create_symbol_list(struct kpatch_elf *kelf)
|
||||||
ERROR("couldn't find section for symbol %s\n",
|
ERROR("couldn't find section for symbol %s\n",
|
||||||
sym->name);
|
sym->name);
|
||||||
|
|
||||||
if (is_bundleable(sym)) {
|
if (sym->type == STT_SECTION) {
|
||||||
if (sym->sym.st_value != 0) {
|
|
||||||
#ifdef __powerpc__
|
|
||||||
if (!is_localentry_sym(sym))
|
|
||||||
#endif
|
|
||||||
ERROR("symbol %s at offset %lu within section %s, expected 0",
|
|
||||||
sym->name, sym->sym.st_value, sym->sec->name);
|
|
||||||
}
|
|
||||||
|
|
||||||
sym->sec->sym = sym;
|
|
||||||
|
|
||||||
} else if (sym->type == STT_SECTION) {
|
|
||||||
sym->sec->secsym = sym;
|
sym->sec->secsym = sym;
|
||||||
/* use the section name as the symbol name */
|
/* use the section name as the symbol name */
|
||||||
sym->name = sym->sec->name;
|
sym->name = sym->sec->name;
|
||||||
|
|
Loading…
Reference in New Issue