History

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. The GOT offset is thus saved in a 31 bit value. Make sure to divide by 2 (right shift by 1) an offset before storing it there and conversely to multiply the value by 2 (left shift by 1) before using it.

Thomas Preud'homme committed 14 years ago

Commit 891dfcd1 parent e07802e2 files · +61 −26Browse files

Unified · Split

2 files
  1. tcc.h +8 −3
  2. tccelf.c +53 −23
tcc.h+8−3
@@ -33,6 +33,7 @@ · 32 unmodified lines
3333
3434 #include <stdlib.h>
3535 #include <stdio.h>
36+#include <limits.h>
3637 #include <stdarg.h>
3738 #include <string.h>
3839 #include <errno.h>
@@ -524,11 +525,15 @@ struct TCCState { · 485 unmodified lines
524525 Section **priv_sections;
525526 int nb_priv_sections; /* number of private sections */
526527
527− /* got handling */
528+ /* got & plt handling */
528529 Section *got;
529530 Section *plt;
530− unsigned long *got_offsets;
531− int nb_got_offsets;
531+ struct {
532+ unsigned long plt_thumb_stub:1;
533+ /* mult by 2 (or left shift by 1) before use */
534+ unsigned long got_offset:(sizeof(long)*CHAR_BIT-1);
535+ } *sym_infos;
536+ int nb_sym_infos;
532537 /* give the correspondance from symtab indexes to dynsym indexes */
533538 int *symtab_to_dynsym;
534539
tccelf.c+53−23
@@ -581,7 +581,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 580 unmodified lines
581581 break;
582582 case R_386_GOT32:
583583 /* we load the got offset */
584− *(int *)ptr += s1->got_offsets[sym_index];
584+ *(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
585585 break;
586586 case R_386_16:
587587 if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
@@ -758,7 +758,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 170 unmodified lines
758758 break;
759759 case R_ARM_GOT_BREL:
760760 /* we load the got offset */
761− *(int *)ptr += s1->got_offsets[sym_index];
761+ *(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
762762 break;
763763 case R_ARM_COPY:
764764 break;
@@ -864,14 +864,14 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 99 unmodified lines
864864 }
865865 #endif
866866 *(int *)ptr += (s1->got->sh_addr - addr +
867− s1->got_offsets[sym_index] - 4);
867+ (s1->sym_infos[sym_index].got_offset << 1) - 4);
868868 break;
869869 case R_X86_64_GOTTPOFF:
870870 *(int *)ptr += val - s1->got->sh_addr;
871871 break;
872872 case R_X86_64_GOT32:
873873 /* we load the got offset */
874− *(int *)ptr += s1->got_offsets[sym_index];
874+ *(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
875875 break;
876876 #else
877877 #error unsupported processor
@@ -941,23 +941,36 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr) · 63 unmodified lines
941941 return count;
942942 }
943943
944−static void put_got_offset(TCCState *s1, int index, unsigned long val)
944+static void put_sym_info(TCCState *s1, int index)
945945 {
946946 int n;
947− unsigned long *tab;
947+ typeof(s1->sym_infos) tab;
948948
949− if (index >= s1->nb_got_offsets) {
949+ if (index >= s1->nb_sym_infos) {
950950 /* find immediately bigger power of 2 and reallocate array */
951951 n = 1;
952952 while (index >= n)
953953 n *= 2;
954− tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long));
955− s1->got_offsets = tab;
956− memset(s1->got_offsets + s1->nb_got_offsets, 0,
957− (n - s1->nb_got_offsets) * sizeof(unsigned long));
958− s1->nb_got_offsets = n;
954+ tab = tcc_realloc(s1->sym_infos, n * sizeof(unsigned long));
955+ s1->sym_infos = tab;
956+ memset(s1->sym_infos + s1->nb_sym_infos, 0,
957+ (n - s1->nb_sym_infos) * sizeof(unsigned long));
958+ s1->nb_sym_infos = n;
959959 }
960− s1->got_offsets[index] = val;
960+}
961+
962+#ifdef TCC_TARGET_ARM
963+static void put_plt_thumb_stub(TCCState *s1, int index, unsigned char bit)
964+{
965+ put_sym_info(s1, index);
966+ s1->sym_infos[index].plt_thumb_stub = bit;
967+}
968+#endif
969+
970+static void put_got_offset(TCCState *s1, int index, unsigned long val)
971+{
972+ put_sym_info(s1, index);
973+ s1->sym_infos[index].got_offset = val >> 1;
961974 }
962975
963976 /* XXX: suppress that */
@@ -1021,8 +1034,8 @@ static void put_got_entry(TCCState *s1, · 57 unmodified lines
10211034 build_got(s1);
10221035
10231036 /* if a got entry already exists for that symbol, no need to add one */
1024− if (sym_index < s1->nb_got_offsets &&
1025− s1->got_offsets[sym_index] != 0)
1037+ if (sym_index < s1->nb_sym_infos &&
1038+ s1->sym_infos[sym_index].got_offset << 1)
10261039 return;
10271040
10281041 put_got_offset(s1, sym_index, s1->got->data_offset);
@@ -1102,10 +1115,13 @@ static void put_got_entry(TCCState *s1, · 73 unmodified lines
11021115 put32(p + 12, 0xe5bef008);
11031116 }
11041117
1105− p = section_ptr_add(plt, 20);
1106− put32(p , 0x4778); // bx pc
1107− put32(p+2, 0x46c0); // nop
1108− p += 4;
1118+ if (s1->sym_infos[sym_index].plt_thumb_stub) {
1119+ p = section_ptr_add(plt, 20);
1120+ put32(p , 0x4778); // bx pc
1121+ put32(p+2, 0x46c0); // nop
1122+ p += 4;
1123+ } else
1124+ p = section_ptr_add(plt, 16);
11091125 put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT
11101126 put32(p+4, 0xe08fc00c); // add ip, pc, ip // absolute address or offset
11111127 put32(p+8, 0xe59cf000); // ldr pc, [ip] // load absolute address or load offset
@@ -1492,9 +1508,9 @@ ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel) · 380 unmodified lines
14921508 ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
14931509 unsigned long offset;
14941510
1495− if (sym_index >= s1->nb_got_offsets)
1511+ if (sym_index >= s1->nb_sym_infos)
14961512 return;
1497− offset = s1->got_offsets[sym_index];
1513+ offset = s1->sym_infos[sym_index].got_offset << 1;
14981514 section_reserve(s1->got, offset + PTR_SIZE);
14991515 #ifdef TCC_TARGET_X86_64
15001516 /* only works for x86-64 */
@@ -2068,7 +2084,8 @@ static int elf_output_file(TCCState *s1, const char *filename) · 567 unmodified lines
20682084 x=s1->got->sh_addr - s1->plt->sh_addr - 12;
20692085 p += 16;
20702086 while (p < p_end) {
2071− p += 4;
2087+ if (get32(p) == 0x46c04778) /* PLT Thumb stub present */
2088+ p += 4;
20722089 put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
20732090 p += 16;
20742091 }
@@ -2302,7 +2319,7 @@ static int elf_output_file(TCCState *s1, const char *filename) · 227 unmodified lines
23022319 tcc_free(s1->symtab_to_dynsym);
23032320 tcc_free(section_order);
23042321 tcc_free(phdr);
2305− tcc_free(s1->got_offsets);
2322+ tcc_free(s1->sym_infos);
23062323 return ret;
23072324 }
23082325
@@ -2597,6 +2614,19 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, · 288 unmodified lines
25972614 rel->r_info = ELFW(R_INFO)(sym_index, type);
25982615 /* offset the relocation offset */
25992616 rel->r_offset += offseti;
2617+#ifdef TCC_TARGET_ARM
2618+ /* Jumps and branches from a Thumb code to a PLT entry need
2619+ special handling since PLT entries are ARM code.
2620+ Unconditional bl instructions referencing PLT entries are
2621+ handled by converting these instructions into blx
2622+ instructions. Other case of instructions referencing a PLT
2623+ entry require to add a Thumb stub before the PLT entry to
2624+ switch to ARM mode. We set bit 0 of the got offset of a
2625+ symbol to indicate such a case. */
2626+ if (type == R_ARM_THM_JUMP24) {
2627+ put_plt_thumb_stub(s1, sym_index, 1);
2628+ }
2629+#endif
26002630 }
26012631 break;
26022632 default:

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