Greetings everyone, while working on adding support for R_ARM_THM_JUMP24 to a PLT entry, I needed to store an extra information for some symbols about the nature of the call sites of a PLT entry. Since most symbols don't have a PLT entry, I was reluctant in adding even a byte for all symbols in a set of object file. Then I realized bit 0 of entries in the got_offsets array (in TCCState) is always 0 and could be reused for my purpose.
Currently (see attached patch 0002-Generate-PLT-thumb-stub-only-when- necessary.patch), I reuse the bit 0 without using bitfields. This has the advantage of being able to reuse put_got_offset() function by changing the assignment of the value with a bit ORing but doesn't mark explicitely to the compiler what's going on. On the other hand, I could use bitfields but that would require some more modifications to put_got_offset to be able to set a got_offset and/or the bit 0. Note that in both cases all access to got_offset needs to be changed: if bitfields is used the value of got_offset needs to be shifted by one bit to the left, else, the value needs to be ANDed with -2 to ignore bit 0. What's your opinion about it? What's the best approach? Is there another one possible? (I initially thought about storing the extra information in a hash table but it requires to add an hashtable implementation while I could reuse the unused bit of got_offsets). Best regards, Thomas Preud'homme
From f2365979217811d651dd9c029196906fede16084 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme <[email protected]> Date: Sun, 28 Oct 2012 19:38:38 +0100 Subject: [PATCH 1/2] Support R_ARM_THM_JUMP24 relocation to plt Add thumb stubs switching from thumb mode to arm mode to *all* PLT entries so that R_ARM_THM_JUMP24 relocations to PLT entries can be satisfied. --- tccelf.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tccelf.c b/tccelf.c index e5bb1cb..d0e4c3b 100644 --- a/tccelf.c +++ b/tccelf.c @@ -638,7 +638,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) case R_ARM_THM_JUMP24: { int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; - int to_thumb, is_call, blx_bit = 1 << 12; + int to_thumb, is_call, to_plt, blx_bit = 1 << 12; + Section *plt; /* weak reference */ if (sym->st_shndx == SHN_UNDEF && @@ -662,9 +663,14 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) /* Relocation infos */ to_thumb = val & 1; + plt = s1->plt; + to_plt = (val >= plt->sh_addr) && + (val < plt->sh_addr + plt->data_offset); is_call = (type == R_ARM_THM_CALL); /* Compute final offset */ + if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ + x -= 4; x += val - addr; if (!to_thumb && is_call) { blx_bit = 0; /* bl -> blx */ @@ -675,9 +681,9 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) * offset must not be out of range * if target is to be entered in arm mode: - bit 1 must not set - - instruction must be a call (bl) */ + - instruction must be a call (bl) or a jump to PLT */ if (!to_thumb || x >= 0x1000000 || x < -0x1000000) - if (to_thumb || (val & 2) || !is_call) + if (to_thumb || (val & 2) || (!is_call && !to_plt)) tcc_error("can't relocate value at %x",addr); /* Compute and store final offset */ @@ -1096,10 +1102,13 @@ static void put_got_entry(TCCState *s1, put32(p + 12, 0xe5bef008); } - p = section_ptr_add(plt, 16); - put32(p , 0xe59fc004); - put32(p+4, 0xe08fc00c); - put32(p+8, 0xe59cf000); + p = section_ptr_add(plt, 20); + put32(p , 0x4778); // bx pc + put32(p+2, 0x46c0); // nop + p += 4; + put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT + put32(p+4, 0xe08fc00c); // add ip, pc, ip // absolute address or offset + put32(p+8, 0xe59cf000); // ldr pc, [ip] // load absolute address or load offset put32(p+12, s1->got->data_offset); /* the symbol is modified so that it will be relocated to @@ -2057,8 +2066,9 @@ static int elf_output_file(TCCState *s1, const char *filename) #elif defined(TCC_TARGET_ARM) int x; x=s1->got->sh_addr - s1->plt->sh_addr - 12; - p +=16; + p += 16; while (p < p_end) { + p += 4; put32(p + 12, x + get32(p + 12) + s1->plt->data - p); p += 16; } -- 1.7.10.4
From 2cb6e93e9af77a2e4ff20bd5119dbd7fdc6aeea4 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme <[email protected]> Date: Sun, 4 Nov 2012 00:40:05 +0100 Subject: [PATCH 2/2] Generate PLT thumb stub only when necessary Generate PLT thumb stub for an ARM PLT entry only when at least one Thumb instruction branches to that entry. Warning: To save space, this commit reuses the bit 0 of entries of got_offsets array. Make sure to ignore this bit when using the GOT offset in one of these entries. --- tcc.h | 2 +- tccelf.c | 41 +++++++++++++++++++++++++++++------------ 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/tcc.h b/tcc.h index 4e88782..25c160c 100644 --- a/tcc.h +++ b/tcc.h @@ -527,7 +527,7 @@ struct TCCState { /* got handling */ Section *got; Section *plt; - unsigned long *got_offsets; + unsigned long *got_offsets; /* bit 0 set = PLT entry requires thumb stub */ int nb_got_offsets; /* give the correspondance from symtab indexes to dynsym indexes */ int *symtab_to_dynsym; diff --git a/tccelf.c b/tccelf.c index d0e4c3b..a12dd24 100644 --- a/tccelf.c +++ b/tccelf.c @@ -581,7 +581,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) break; case R_386_GOT32: /* we load the got offset */ - *(int *)ptr += s1->got_offsets[sym_index]; + *(int *)ptr += s1->got_offsets[sym_index] & -2; break; case R_386_16: if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) { @@ -758,7 +758,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) break; case R_ARM_GOT_BREL: /* we load the got offset */ - *(int *)ptr += s1->got_offsets[sym_index]; + *(int *)ptr += s1->got_offsets[sym_index] & -2; break; case R_ARM_COPY: break; @@ -864,14 +864,14 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) } #endif *(int *)ptr += (s1->got->sh_addr - addr + - s1->got_offsets[sym_index] - 4); + (s1->got_offsets[sym_index] & -2) - 4); break; case R_X86_64_GOTTPOFF: *(int *)ptr += val - s1->got->sh_addr; break; case R_X86_64_GOT32: /* we load the got offset */ - *(int *)ptr += s1->got_offsets[sym_index]; + *(int *)ptr += s1->got_offsets[sym_index] & -2; break; #else #error unsupported processor @@ -957,7 +957,7 @@ static void put_got_offset(TCCState *s1, int index, unsigned long val) (n - s1->nb_got_offsets) * sizeof(unsigned long)); s1->nb_got_offsets = n; } - s1->got_offsets[index] = val; + s1->got_offsets[index] |= val; } /* XXX: suppress that */ @@ -1022,7 +1022,7 @@ static void put_got_entry(TCCState *s1, /* if a got entry already exists for that symbol, no need to add one */ if (sym_index < s1->nb_got_offsets && - s1->got_offsets[sym_index] != 0) + s1->got_offsets[sym_index] & -2) return; put_got_offset(s1, sym_index, s1->got->data_offset); @@ -1102,10 +1102,13 @@ static void put_got_entry(TCCState *s1, put32(p + 12, 0xe5bef008); } - p = section_ptr_add(plt, 20); - put32(p , 0x4778); // bx pc - put32(p+2, 0x46c0); // nop - p += 4; + if (s1->got_offsets[sym_index] & 1) { + p = section_ptr_add(plt, 20); + put32(p , 0x4778); // bx pc + put32(p+2, 0x46c0); // nop + p += 4; + } else + p = section_ptr_add(plt, 16); put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT put32(p+4, 0xe08fc00c); // add ip, pc, ip // absolute address or offset put32(p+8, 0xe59cf000); // ldr pc, [ip] // load absolute address or load offset @@ -1494,7 +1497,7 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) if (sym_index >= s1->nb_got_offsets) return; - offset = s1->got_offsets[sym_index]; + offset = s1->got_offsets[sym_index] & -2; section_reserve(s1->got, offset + PTR_SIZE); #ifdef TCC_TARGET_X86_64 /* only works for x86-64 */ @@ -2068,7 +2071,8 @@ static int elf_output_file(TCCState *s1, const char *filename) x=s1->got->sh_addr - s1->plt->sh_addr - 12; p += 16; while (p < p_end) { - p += 4; + if (get32(p) == 0x46c04778) /* PLT Thumb stub present */ + p += 4; put32(p + 12, x + get32(p + 12) + s1->plt->data - p); p += 16; } @@ -2597,6 +2601,19 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, rel->r_info = ELFW(R_INFO)(sym_index, type); /* offset the relocation offset */ rel->r_offset += offseti; +#ifdef TCC_TARGET_ARM + /* Jumps and branches from a Thumb code to a PLT entry need + special handling since PLT entries are ARM code. + Unconditional bl instructions referencing PLT entries are + handled by converting these instructions into blx + instructions. Other case of instructions referencing a PLT + entry require to add a Thumb stub before the PLT entry to + switch to ARM mode. We set bit 0 of the got offset of a + symbol to indicate such a case. */ + if (type == R_ARM_THM_JUMP24) { + put_got_offset(s1, sym_index, 1); + } +#endif } break; default: -- 1.7.10.4
signature.asc
Description: This is a digitally signed message part.
_______________________________________________ Tinycc-devel mailing list [email protected] https://lists.nongnu.org/mailman/listinfo/tinycc-devel
