aboutsummaryrefslogtreecommitdiff
path: root/tccgen.c
diff options
context:
space:
mode:
authorMichael Matz <matz@suse.de>2016-10-08 02:44:17 +0200
committerMichael Matz <matz@suse.de>2016-12-15 17:49:53 +0100
commitddd461dcc866d17f1c89137dc275ce1da95e7be2 (patch)
tree1585ee439f895aeb049e8d3792748451ca768d86 /tccgen.c
parentf081acbfba84ffdf1e479f932906bf10f88cd1c2 (diff)
downloadtinycc-ddd461dcc866d17f1c89137dc275ce1da95e7be2.tar.gz
tinycc-ddd461dcc866d17f1c89137dc275ce1da95e7be2.tar.bz2
Fix initializing members multiple times
When intializing members where the initializer needs relocations and the member is initialized multiple times we can't allow that to lead to multiple relocations to the same place. The last one must win.
Diffstat (limited to 'tccgen.c')
-rw-r--r--tccgen.c11
1 files changed, 11 insertions, 0 deletions
diff --git a/tccgen.c b/tccgen.c
index 5c2acf8..5c74971 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -6019,6 +6019,12 @@ static void init_putv(CType *type, Section *sec, unsigned long c)
continue;
if (rel->r_offset < esym->st_value)
break;
+ /* Note: if the same fields are initialized multiple
+ times (possible with designators) then we possibly
+ add multiple relocations for the same offset here.
+ That would lead to wrong code, the last reloc needs
+ to win. We clean this up later after the whole
+ initializer is parsed. */
put_elf_reloca(symtab_section, sec,
c + rel->r_offset - esym->st_value,
ELFW(R_TYPE)(rel->r_info),
@@ -6602,7 +6608,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r,
vla_sp_loc = addr;
vlas_in_scope++;
} else if (has_init) {
+ size_t oldreloc_offset = 0;
+ if (sec && sec->reloc)
+ oldreloc_offset = sec->reloc->data_offset;
decl_initializer(type, sec, addr, 1, 0);
+ if (sec && sec->reloc)
+ squeeze_multi_relocs(sec, oldreloc_offset);
/* patch flexible array member size back to -1, */
/* for possible subsequent similar declarations */
if (flexible_array)