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.
Unified · Split
| @@ -638,7 +638,8 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 637 unmodified lines | ||
| 638 | 638 | case R_ARM_THM_JUMP24: |
| 639 | 639 | { |
| 640 | 640 | int x, hi, lo, s, j1, j2, i1, i2, imm10, imm11; |
| 641 | − int to_thumb, is_call, blx_bit = 1 << 12; | |
| 641 | + int to_thumb, is_call, to_plt, blx_bit = 1 << 12; | |
| 642 | + Section *plt; | |
| 642 | 643 | |
| 643 | 644 | /* weak reference */ |
| 644 | 645 | if (sym->st_shndx == SHN_UNDEF && |
| @@ -662,9 +663,14 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 17 unmodified lines | ||
| 662 | 663 | |
| 663 | 664 | /* Relocation infos */ |
| 664 | 665 | to_thumb = val & 1; |
| 666 | + plt = s1->plt; | |
| 667 | + to_plt = (val >= plt->sh_addr) && | |
| 668 | + (val < plt->sh_addr + plt->data_offset); | |
| 665 | 669 | is_call = (type == R_ARM_THM_CALL); |
| 666 | 670 | |
| 667 | 671 | /* Compute final offset */ |
| 672 | + if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ | |
| 673 | + x -= 4; | |
| 668 | 674 | x += val - addr; |
| 669 | 675 | if (!to_thumb && is_call) { |
| 670 | 676 | blx_bit = 0; /* bl -> blx */ |
| @@ -675,9 +681,9 @@ ST_FUNC void relocate_section(TCCState *s1, Section *s) · 4 unmodified lines | ||
| 675 | 681 | * offset must not be out of range |
| 676 | 682 | * if target is to be entered in arm mode: |
| 677 | 683 | - bit 1 must not set |
| 678 | − - instruction must be a call (bl) */ | |
| 684 | + - instruction must be a call (bl) or a jump to PLT */ | |
| 679 | 685 | if (!to_thumb || x >= 0x1000000 || x < -0x1000000) |
| 680 | − if (to_thumb || (val & 2) || !is_call) | |
| 686 | + if (to_thumb || (val & 2) || (!is_call && !to_plt)) | |
| 681 | 687 | tcc_error("can't relocate value at %x",addr); |
| 682 | 688 | |
| 683 | 689 | /* Compute and store final offset */ |
| @@ -1096,10 +1102,13 @@ static void put_got_entry(TCCState *s1, · 412 unmodified lines | ||
| 1096 | 1102 | put32(p + 12, 0xe5bef008); |
| 1097 | 1103 | } |
| 1098 | 1104 | |
| 1099 | − p = section_ptr_add(plt, 16); | |
| 1100 | − put32(p , 0xe59fc004); | |
| 1101 | − put32(p+4, 0xe08fc00c); | |
| 1102 | − put32(p+8, 0xe59cf000); | |
| 1105 | + p = section_ptr_add(plt, 20); | |
| 1106 | + put32(p , 0x4778); // bx pc | |
| 1107 | + put32(p+2, 0x46c0); // nop | |
| 1108 | + p += 4; | |
| 1109 | + put32(p , 0xe59fc004); // ldr ip, [pc, #4] // offset in GOT | |
| 1110 | + 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 offset | |
| 1103 | 1112 | put32(p+12, s1->got->data_offset); |
| 1104 | 1113 | |
| 1105 | 1114 | /* 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) · 951 unmodified lines | ||
| 2057 | 2066 | #elif defined(TCC_TARGET_ARM) |
| 2058 | 2067 | int x; |
| 2059 | 2068 | x=s1->got->sh_addr - s1->plt->sh_addr - 12; |
| 2060 | − p +=16; | |
| 2069 | + p += 16; | |
| 2061 | 2070 | while (p < p_end) { |
| 2071 | + p += 4; | |
| 2062 | 2072 | put32(p + 12, x + get32(p + 12) + s1->plt->data - p); |
| 2063 | 2073 | p += 16; |
| 2064 | 2074 | } |