aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tccgen.c26
-rw-r--r--tests/tests2/86-struct-init.c29
2 files changed, 55 insertions, 0 deletions
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 <stdio.h>
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;
}