From 7ab35c6265425a81c14bc313eb4c834985a73ddb Mon Sep 17 00:00:00 2001 From: Michael Matz Date: Mon, 3 Oct 2016 19:21:10 +0200 Subject: [PATCH] struct-init: Copy relocs for compound literals When copying the content of compound literals we must include relocations as well. --- tccgen.c | 26 ++++++++++++++++++++++++++ tests/tests2/86-struct-init.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/tccgen.c b/tccgen.c index f9d4a7c..79ec789 100644 --- a/tccgen.c +++ b/tccgen.c @@ -5995,9 +5995,35 @@ static void init_putv(CType *type, Section *sec, unsigned long c) /* These come from compound literals, memcpy stuff over. */ Section *ssec; ElfW(Sym) *esym; + ElfW_Rel *rel; esym = &((ElfW(Sym) *)symtab_section->data)[vtop->sym->c]; ssec = tcc_state->sections[esym->st_shndx]; memmove (ptr, ssec->data + esym->st_value, size); + if (ssec->reloc) { + /* We need to copy over all memory contents, and that + includes relocations. Use the fact that relocs are + created it order, so look from the end of relocs + until we hit one before the copied region. */ + int num_relocs = ssec->reloc->data_offset / sizeof(*rel); + rel = (ElfW_Rel*)(ssec->reloc->data + ssec->reloc->data_offset); + while (num_relocs--) { + rel--; + if (rel->r_offset >= esym->st_value + size) + continue; + if (rel->r_offset < esym->st_value) + break; + put_elf_reloca(symtab_section, sec, + c + rel->r_offset - esym->st_value, + ELFW(R_TYPE)(rel->r_info), + ELFW(R_SYM)(rel->r_info), +#if defined(TCC_TARGET_ARM64) || defined(TCC_TARGET_X86_64) + rel->r_addend +#else + 0 +#endif + ); + } + } } else { if ((vtop->r & VT_SYM) && (bt == VT_BYTE || diff --git a/tests/tests2/86-struct-init.c b/tests/tests2/86-struct-init.c index 3cf25c7..8d27719 100644 --- a/tests/tests2/86-struct-init.c +++ b/tests/tests2/86-struct-init.c @@ -109,6 +109,21 @@ struct pkthdr { struct in6_addr daddr, saddr; }; struct pkthdr phdr = { { { 6,5,4,3 } }, { { 9,8,7,6 } } }; + +struct Wrap { + void *func; +}; +int global; +void inc_global (void) +{ + global++; +} + +struct Wrap global_wrap[] = { + ((struct Wrap) {inc_global}), + inc_global, +}; + #include void print_ (const char *name, const u8 *p, long size) { @@ -171,6 +186,19 @@ void foo (struct W *w, struct pkthdr *phdr_) } #endif +void test_compound_with_relocs (void) +{ + struct Wrap local_wrap[] = { + ((struct Wrap) {inc_global}), + inc_global, + }; + void (*p)(void); + p = global_wrap[0].func; p(); + p = global_wrap[1].func; p(); + p = local_wrap[0].func; p(); + p = local_wrap[1].func; p(); +} + int main() { print(ce); @@ -195,5 +223,6 @@ int main() print(phdr); foo(&gw, &phdr); //printf("q: %s\n", q); + test_compound_with_relocs(); return 0; }