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
33 33
34#include <stdlib.h>34#include <stdlib.h>
35#include <stdio.h>35#include <stdio.h>
36#include <limits.h>
36#include <stdarg.h>37#include <stdarg.h>
37#include <string.h>38#include <string.h>
38#include <errno.h>39#include <errno.h>
@@ -524,11 +525,15 @@ struct TCCState { · 485 unmodified lines
524 Section **priv_sections;525 Section **priv_sections;
525 int nb_priv_sections; /* number of private sections */526 int nb_priv_sections; /* number of private sections */
526 527
527 /* got handling */528 /* got & plt handling */
528 Section *got;529 Section *got;
529 Section *plt;530 Section *plt;
530 unsigned long *got_offsets;531 struct {
531 int nb_got_offsets;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;
532 /* give the correspondance from symtab indexes to dynsym indexes */537 /* give the correspondance from symtab indexes to dynsym indexes */
533 int *symtab_to_dynsym;538 int *symtab_to_dynsym;
534 539
tccelf.c+53−23
@@ -581,7 +581,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 580 unmodified lines
581 break;581 break;
582 case R_386_GOT32:582 case R_386_GOT32:
583 /* we load the got offset */583 /* we load the got offset */
584 *(int *)ptr += s1->got_offsets[sym_index];584 *(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
585 break;585 break;
586 case R_386_16:586 case R_386_16:
587 if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {587 if (s1->output_format != TCC_OUTPUT_FORMAT_BINARY) {
@@ -758,7 +758,7 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 170 unmodified lines
758 break;758 break;
759 case R_ARM_GOT_BREL:759 case R_ARM_GOT_BREL:
760 /* we load the got offset */760 /* we load the got offset */
761 *(int *)ptr += s1->got_offsets[sym_index];761 *(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
762 break;762 break;
763 case R_ARM_COPY:763 case R_ARM_COPY:
764 break;764 break;
@@ -864,14 +864,14 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 99 unmodified lines
864 }864 }
865#endif865#endif
866 *(int *)ptr += (s1->got->sh_addr - addr +866 *(int *)ptr += (s1->got->sh_addr - addr +
867 s1->got_offsets[sym_index] - 4);867 (s1->sym_infos[sym_index].got_offset << 1) - 4);
868 break;868 break;
869 case R_X86_64_GOTTPOFF:869 case R_X86_64_GOTTPOFF:
870 *(int *)ptr += val - s1->got->sh_addr;870 *(int *)ptr += val - s1->got->sh_addr;
871 break;871 break;
872 case R_X86_64_GOT32:872 case R_X86_64_GOT32:
873 /* we load the got offset */873 /* we load the got offset */
874 *(int *)ptr += s1->got_offsets[sym_index];874 *(int *)ptr += s1->sym_infos[sym_index].got_offset << 1;
875 break;875 break;
876#else876#else
877#error unsupported processor877#error unsupported processor
@@ -941,23 +941,36 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr) · 63 unmodified lines
941 return count;941 return count;
942}942}
943 943
944static void put_got_offset(TCCState *s1, int index, unsigned long val)944static void put_sym_info(TCCState *s1, int index)
945{945{
946 int n;946 int n;
947 unsigned long *tab;947 typeof(s1->sym_infos) tab;
948 948
949 if (index >= s1->nb_got_offsets) {949 if (index >= s1->nb_sym_infos) {
950 /* find immediately bigger power of 2 and reallocate array */950 /* find immediately bigger power of 2 and reallocate array */
951 n = 1;951 n = 1;
952 while (index >= n)952 while (index >= n)
953 n *= 2;953 n *= 2;
954 tab = tcc_realloc(s1->got_offsets, n * sizeof(unsigned long));954 tab = tcc_realloc(s1->sym_infos, n * sizeof(unsigned long));
955 s1->got_offsets = tab;955 s1->sym_infos = tab;
956 memset(s1->got_offsets + s1->nb_got_offsets, 0,956 memset(s1->sym_infos + s1->nb_sym_infos, 0,
957 (n - s1->nb_got_offsets) * sizeof(unsigned long));957 (n - s1->nb_sym_infos) * sizeof(unsigned long));
958 s1->nb_got_offsets = n;958 s1->nb_sym_infos = n;
959 }959 }
960 s1->got_offsets[index] = val;960}
961
962#ifdef TCC_TARGET_ARM
963static 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
970static 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;
961}974}
962 975
963/* XXX: suppress that */976/* XXX: suppress that */
@@ -1021,8 +1034,8 @@ static void put_got_entry(TCCState *s1, · 57 unmodified lines
1021 build_got(s1);1034 build_got(s1);
1022 1035
1023 /* if a got entry already exists for that symbol, no need to add one */1036 /* if a got entry already exists for that symbol, no need to add one */
1024 if (sym_index < s1->nb_got_offsets &&1037 if (sym_index < s1->nb_sym_infos &&
1025 s1->got_offsets[sym_index] != 0)1038 s1->sym_infos[sym_index].got_offset << 1)
1026 return;1039 return;
1027 1040
1028 put_got_offset(s1, sym_index, s1->got->data_offset);1041 put_got_offset(s1, sym_index, s1->got->data_offset);
@@ -1102,10 +1115,13 @@ static void put_got_entry(TCCState *s1, · 73 unmodified lines
1102 put32(p + 12, 0xe5bef008);1115 put32(p + 12, 0xe5bef008);
1103 }1116 }
1104 1117
1105 p = section_ptr_add(plt, 20);1118 if (s1->sym_infos[sym_index].plt_thumb_stub) {
1106 put32(p , 0x4778); // bx pc1119 p = section_ptr_add(plt, 20);
1107 put32(p+2, 0x46c0); // nop1120 put32(p , 0x4778); // bx pc
1108 p += 4;1121 put32(p+2, 0x46c0); // nop
1122 p += 4;
1123 } else
1124 p = section_ptr_add(plt, 16);
1109 put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT1125 put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT
1110 put32(p+4, 0xe08fc00c); // add ip, pc, ip // absolute address or offset1126 put32(p+4, 0xe08fc00c); // add ip, pc, ip // absolute address or offset
1111 put32(p+8, 0xe59cf000); // ldr pc, [ip] // load absolute address or load offset1127 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
1492 ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];1508 ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
1493 unsigned long offset;1509 unsigned long offset;
1494 1510
1495 if (sym_index >= s1->nb_got_offsets)1511 if (sym_index >= s1->nb_sym_infos)
1496 return;1512 return;
1497 offset = s1->got_offsets[sym_index];1513 offset = s1->sym_infos[sym_index].got_offset << 1;
1498 section_reserve(s1->got, offset + PTR_SIZE);1514 section_reserve(s1->got, offset + PTR_SIZE);
1499#ifdef TCC_TARGET_X86_641515#ifdef TCC_TARGET_X86_64
1500 /* only works for x86-64 */1516 /* only works for x86-64 */
@@ -2068,7 +2084,8 @@ static int elf_output_file(TCCState *s1, const char *filename) · 567 unmodified lines
2068 x=s1->got->sh_addr - s1->plt->sh_addr - 12;2084 x=s1->got->sh_addr - s1->plt->sh_addr - 12;
2069 p += 16;2085 p += 16;
2070 while (p < p_end) {2086 while (p < p_end) {
2071 p += 4;2087 if (get32(p) == 0x46c04778) /* PLT Thumb stub present */
2088 p += 4;
2072 put32(p + 12, x + get32(p + 12) + s1->plt->data - p);2089 put32(p + 12, x + get32(p + 12) + s1->plt->data - p);
2073 p += 16;2090 p += 16;
2074 }2091 }
@@ -2302,7 +2319,7 @@ static int elf_output_file(TCCState *s1, const char *filename) · 227 unmodified lines
2302 tcc_free(s1->symtab_to_dynsym);2319 tcc_free(s1->symtab_to_dynsym);
2303 tcc_free(section_order);2320 tcc_free(section_order);
2304 tcc_free(phdr);2321 tcc_free(phdr);
2305 tcc_free(s1->got_offsets);2322 tcc_free(s1->sym_infos);
2306 return ret;2323 return ret;
2307}2324}
2308 2325
@@ -2597,6 +2614,19 @@ ST_FUNC int tcc_load_object_file(TCCState *s1, · 288 unmodified lines
2597 rel->r_info = ELFW(R_INFO)(sym_index, type);2614 rel->r_info = ELFW(R_INFO)(sym_index, type);
2598 /* offset the relocation offset */2615 /* offset the relocation offset */
2599 rel->r_offset += offseti;2616 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
2600 }2630 }
2601 break;2631 break;
2602 default:2632 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