History

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.

Michael Matz committed 10 years ago

Commit ddd461d1 parent f081acb5 files · +73 −0Browse files

Unified · Split

5 files
  1. tcc.h +2 −0
  2. tccelf.c +37 −0
  3. tccgen.c +11 −0
  4. tests/tests2/86-struct-init.c +20 −0
  5. tests/tests2/86-struct-init.expect +3 −0
tcc.h+2−0
@@ -1384,6 +1384,8 @@ ST_FUNC void tcc_add_runtime(TCCState *s1); · 1383 unmodified lines
13841384
13851385 ST_FUNC void build_got_entries(TCCState *s1);
13861386 ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc);
1387+ST_FUNC void squeeze_multi_relocs(Section *sec, size_t oldrelocoffset);
1388+
13871389 ST_FUNC addr_t get_elf_sym_addr(TCCState *s, const char *name, int err);
13881390 #if defined TCC_IS_NATIVE || defined TCC_TARGET_PE
13891391 ST_FUNC void *tcc_get_symbol_err(TCCState *s, const char *name);
tccelf.c+37−0
@@ -535,6 +535,43 @@ ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset, · 534 unmodified lines
535535 put_elf_reloca(symtab, s, offset, type, symbol, 0);
536536 }
537537
538+/* Remove relocations for section S->reloc starting at oldrelocoffset
539+ that are to the same place, retaining the last of them. As side effect
540+ the relocations are sorted. Possibly reduces the number of relocs. */
541+ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset)
542+{
543+ Section *sr = s->reloc;
544+ ElfW_Rel *r, *dest;
545+ ssize_t a;
546+ ElfW(Addr) addr;
547+
548+ if (oldrelocoffset + sizeof(*r) >= sr->data_offset)
549+ return;
550+ /* The relocs we're dealing with are the result of initializer parsing.
551+ So they will be mostly in order and there aren't many of them.
552+ Secondly we need a stable sort (which qsort isn't). We use
553+ a simple insertion sort. */
554+ for (a = oldrelocoffset + sizeof(*r); a < sr->data_offset; a += sizeof(*r)) {
555+ ssize_t i = a - sizeof(*r);
556+ addr = ((ElfW_Rel*)(sr->data + a))->r_offset;
557+ for (; i >= (ssize_t)oldrelocoffset &&
558+ ((ElfW_Rel*)(sr->data + i))->r_offset > addr; i -= sizeof(*r)) {
559+ ElfW_Rel tmp = *(ElfW_Rel*)(sr->data + a);
560+ *(ElfW_Rel*)(sr->data + a) = *(ElfW_Rel*)(sr->data + i);
561+ *(ElfW_Rel*)(sr->data + i) = tmp;
562+ }
563+ }
564+
565+ r = (ElfW_Rel*)(sr->data + oldrelocoffset);
566+ dest = r;
567+ for (; r < (ElfW_Rel*)(sr->data + sr->data_offset); r++) {
568+ if (dest->r_offset != r->r_offset)
569+ dest++;
570+ *dest = *r;
571+ }
572+ sr->data_offset = (unsigned char*)dest - sr->data + sizeof(*r);
573+}
574+
538575 /* put stab debug information */
539576
540577 ST_FUNC void put_stabs(const char *str, int type, int other, int desc,
tccgen.c+11−0
@@ -6019,6 +6019,12 @@ static void init_putv(CType *type, Section *sec, unsigned long c) · 6018 unmodified lines
60196019 continue;
60206020 if (rel->r_offset < esym->st_value)
60216021 break;
6022+ /* Note: if the same fields are initialized multiple
6023+ times (possible with designators) then we possibly
6024+ add multiple relocations for the same offset here.
6025+ That would lead to wrong code, the last reloc needs
6026+ to win. We clean this up later after the whole
6027+ initializer is parsed. */
60226028 put_elf_reloca(symtab_section, sec,
60236029 c + rel->r_offset - esym->st_value,
60246030 ELFW(R_TYPE)(rel->r_info),
@@ -6602,7 +6608,12 @@ static void decl_initializer_alloc(CType *type, AttributeDef *ad, int r, · 577 unmodified lines
66026608 vla_sp_loc = addr;
66036609 vlas_in_scope++;
66046610 } else if (has_init) {
6611+ size_t oldreloc_offset = 0;
6612+ if (sec && sec->reloc)
6613+ oldreloc_offset = sec->reloc->data_offset;
66056614 decl_initializer(type, sec, addr, 1, 0);
6615+ if (sec && sec->reloc)
6616+ squeeze_multi_relocs(sec, oldreloc_offset);
66066617 /* patch flexible array member size back to -1, */
66076618 /* for possible subsequent similar declarations */
66086619 if (flexible_array)
tests/tests2/86-struct-init.c+20−0
@@ -199,6 +199,25 @@ void test_compound_with_relocs (void) · 198 unmodified lines
199199 p = local_wrap[1].func; p();
200200 }
201201
202+void sys_ni(void) { printf("ni\n"); }
203+void sys_one(void) { printf("one\n"); }
204+void sys_two(void) { printf("two\n"); }
205+void sys_three(void) { printf("three\n"); }
206+typedef void (*fptr)(void);
207+const fptr table[3] = {
208+ [0 ... 2] = &sys_ni,
209+ [0] = sys_one,
210+ [1] = sys_two,
211+ [2] = sys_three,
212+};
213+
214+void test_multi_relocs(void)
215+{
216+ int i;
217+ for (i = 0; i < sizeof(table)/sizeof(table[0]); i++)
218+ table[i]();
219+}
220+
202221 int main()
203222 {
204223 print(ce);
@@ -224,5 +243,6 @@ int main() · 19 unmodified lines
224243 foo(&gw, &phdr);
225244 //printf("q: %s\n", q);
226245 test_compound_with_relocs();
246+ test_multi_relocs();
227247 return 0;
228248 }
tests/tests2/86-struct-init.expect+3−0
@@ -35,3 +35,6 @@ lv2: 1 2 3 4 68 69 68 69 0 0 0 0 0 0 0 0 0 0 0 0 2f 30 · 34 unmodified lines
3535 lv3: 7 8 9 a 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 32
3636 lt2: 0 9 9 9 43 43 43 43 42 42 42 0 0 0 0 0 1
3737 flow: 9 8 7 6 0 0 0 0 0 0 0 0 0 0 0 0 6 5 4 3 0 0 0 0 0 0 0 0 0 0 0 0
38+one
39+two
40+three

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t