mirror of
https://github.com/dynup/kpatch
synced 2025-03-30 23:26:23 +00:00
kpatch-build: Support gcc-6 function prologue
With gcc-6 the function prologue is changeg by moving the toc base resolution func - 0x8 bytes: .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 Add support for function prologue, along with gcc-5. Cc: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Kamalesh Babulal <kamalesh@linux.vnet.ibm.com>
This commit is contained in:
parent
77f8fd09f1
commit
e3ccff0cab
@ -2253,6 +2253,27 @@ static void kpatch_create_intermediate_sections(struct kpatch_elf *kelf,
|
|||||||
*/
|
*/
|
||||||
sym_objname = objname;
|
sym_objname = objname;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function prologue generated by gcc6 on ppc64le 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
|
||||||
|
*
|
||||||
|
* first entry past function global entry point is optional
|
||||||
|
* and has the relocation type R_PPC64_ENTRY. We should *not*
|
||||||
|
* skip this entry while building up the rela list, rather
|
||||||
|
* skip it's lookup.
|
||||||
|
*/
|
||||||
|
if (rela->type == R_PPC64_ENTRY)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (rela->sym->bind == STB_LOCAL) {
|
if (rela->sym->bind == STB_LOCAL) {
|
||||||
/* An unchanged local symbol */
|
/* An unchanged local symbol */
|
||||||
ret = lookup_local_symbol(table,
|
ret = lookup_local_symbol(table,
|
||||||
|
@ -243,7 +243,19 @@ static void create_klp_relasecs_and_syms(struct kpatch_elf *kelf, struct section
|
|||||||
rela->offset = toc_offset;
|
rela->offset = toc_offset;
|
||||||
else
|
else
|
||||||
rela->offset = krelas[index].offset;
|
rela->offset = krelas[index].offset;
|
||||||
rela->addend = krelas[index].addend;
|
|
||||||
|
/*
|
||||||
|
* gcc6 adds offset for 0x8 for every local function entry in
|
||||||
|
* .toc section, for avoiding setup of toc but when the previously
|
||||||
|
* local function becomes global, toc is anyways setup. So remove
|
||||||
|
* the wrong addend.
|
||||||
|
*/
|
||||||
|
if (!strcmp(base->name, ".toc") &&
|
||||||
|
rela->sym->type == STT_FUNC && rela->sym->bind == STB_LOCAL) {
|
||||||
|
rela->addend = 0;
|
||||||
|
} else {
|
||||||
|
rela->addend = krelas[index].addend;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,6 +76,50 @@ 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)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* function prologue generated by gcc6 on ppc64le 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 resolved by .TOC.-my_func to a 64-bit offset stored
|
||||||
|
* above the global entry point. my_func st_value is set 0x8, for
|
||||||
|
* calling into the .localentry of the function.
|
||||||
|
*
|
||||||
|
* Number of instructions between global and local entry point of a
|
||||||
|
* function is mostly 8 instructions. i.e st_other == 3. The count of
|
||||||
|
* instruction can be decoded only for local function symbols.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
@ -328,9 +372,14 @@ void kpatch_create_symbol_list(struct kpatch_elf *kelf)
|
|||||||
sym->name);
|
sym->name);
|
||||||
|
|
||||||
if (is_bundleable(sym)) {
|
if (is_bundleable(sym)) {
|
||||||
if (sym->sym.st_value != 0)
|
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",
|
ERROR("symbol %s at offset %lu within section %s, expected 0",
|
||||||
sym->name, sym->sym.st_value, sym->sec->name);
|
sym->name, sym->sym.st_value, sym->sec->name);
|
||||||
|
}
|
||||||
|
|
||||||
sym->sec->sym = sym;
|
sym->sec->sym = sym;
|
||||||
} else if (sym->type == STT_SECTION) {
|
} else if (sym->type == STT_SECTION) {
|
||||||
sym->sec->secsym = sym;
|
sym->sec->secsym = sym;
|
||||||
|
@ -131,6 +131,10 @@ struct rela *find_rela_by_offset(struct section *relasec, unsigned int offset);
|
|||||||
|
|
||||||
int offset_of_string(struct list_head *list, char *name);
|
int offset_of_string(struct list_head *list, char *name);
|
||||||
|
|
||||||
|
#ifndef R_PPC64_ENTRY
|
||||||
|
#define R_PPC64_ENTRY 118
|
||||||
|
#endif
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
* Functions
|
* Functions
|
||||||
* **********/
|
* **********/
|
||||||
|
Loading…
Reference in New Issue
Block a user