Factor most of common logic between targets in build_got_entries by defining target specific info into structures in the backends.
Unified · Split
| @@ -138,6 +138,7 @@ enum { · 137 unmodified lines | |||
| 138 | #define R_DATA_32 R_ARM_ABS32 | 138 | #define R_DATA_32 R_ARM_ABS32 |
| 139 | #define R_DATA_PTR R_ARM_ABS32 | 139 | #define R_DATA_PTR R_ARM_ABS32 |
| 140 | #define R_JMP_SLOT R_ARM_JUMP_SLOT | 140 | #define R_JMP_SLOT R_ARM_JUMP_SLOT |
| 141 | #define R_GLOB_DAT R_ARM_GLOB_DAT | ||
| 141 | #define R_COPY R_ARM_COPY | 142 | #define R_COPY R_ARM_COPY |
| 142 | 143 | ||
| 143 | #define ELF_START_ADDR 0x00008000 | 144 | #define ELF_START_ADDR 0x00008000 |
| @@ -1,6 +1,30 @@ | |||
| 1 | #include "tcc.h" | 1 | #include "tcc.h" |
| 2 | #define HAVE_SECTION_RELOC | 2 | #define HAVE_SECTION_RELOC |
| 3 | 3 | ||
| 4 | ST_DATA struct reloc_info relocs_info[] = { | ||
| 5 | INIT_RELOC_INFO (R_ARM_PC24, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 6 | INIT_RELOC_INFO (R_ARM_CALL, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 7 | INIT_RELOC_INFO (R_ARM_JUMP24, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 8 | INIT_RELOC_INFO (R_ARM_PLT32, 1, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 9 | INIT_RELOC_INFO (R_ARM_THM_PC22, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 10 | INIT_RELOC_INFO (R_ARM_THM_JUMP24, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 11 | INIT_RELOC_INFO (R_ARM_MOVT_ABS, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 12 | INIT_RELOC_INFO (R_ARM_MOVW_ABS_NC, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 13 | INIT_RELOC_INFO (R_ARM_THM_MOVT_ABS, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 14 | INIT_RELOC_INFO (R_ARM_THM_MOVW_ABS_NC, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 15 | INIT_RELOC_INFO (R_ARM_PREL31, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 16 | INIT_RELOC_INFO (R_ARM_ABS32, 0, NO_GOTPLT_ENTRY, 0) | ||
| 17 | INIT_RELOC_INFO (R_ARM_REL32, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 18 | INIT_RELOC_INFO (R_ARM_GOTPC, 0, BUILD_GOT_ONLY, 0) | ||
| 19 | INIT_RELOC_INFO (R_ARM_GOTOFF, 0, BUILD_GOT_ONLY, 0) | ||
| 20 | INIT_RELOC_INFO (R_ARM_GOT32, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 21 | INIT_RELOC_INFO (R_ARM_COPY, 0, NO_GOTPLT_ENTRY, 0) | ||
| 22 | INIT_RELOC_INFO (R_ARM_V4BX, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 23 | INIT_RELOC_INFO (R_ARM_GLOB_DAT, 0, NO_GOTPLT_ENTRY, 0) | ||
| 24 | INIT_RELOC_INFO (R_ARM_JUMP_SLOT, 1, NO_GOTPLT_ENTRY, 0) | ||
| 25 | INIT_RELOC_INFO (R_ARM_NONE, 0, NO_GOTPLT_ENTRY, 0) | ||
| 26 | }; | ||
| 27 | |||
| 4 | void relocate_init(Section *sr) {} | 28 | void relocate_init(Section *sr) {} |
| 5 | 29 | ||
| 6 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) | 30 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) |
| @@ -19,8 +43,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add · 12 unmodified lines | |||
| 19 | { | 43 | { |
| 20 | int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; | 44 | int x, is_thumb, is_call, h, blx_avail, is_bl, th_ko; |
| 21 | x = (*(int *) ptr) & 0xffffff; | 45 | x = (*(int *) ptr) & 0xffffff; |
| 22 | if (sym->st_shndx == SHN_UNDEF || | 46 | if (sym->st_shndx == SHN_UNDEF || sym->st_shndx == SHN_ABS) |
| 23 | s1->output_type == TCC_OUTPUT_MEMORY) | ||
| 24 | val = s1->plt->sh_addr; | 47 | val = s1->plt->sh_addr; |
| 25 | #ifdef DEBUG_RELOC | 48 | #ifdef DEBUG_RELOC |
| 26 | printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); | 49 | printf ("reloc %d: x=0x%x val=0x%x ", type, x, val); |
| @@ -89,6 +112,33 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add · 62 unmodified lines | |||
| 89 | (val < plt->sh_addr + plt->data_offset); | 112 | (val < plt->sh_addr + plt->data_offset); |
| 90 | is_call = (type == R_ARM_THM_PC22); | 113 | is_call = (type == R_ARM_THM_PC22); |
| 91 | 114 | ||
| 115 | if (!to_thumb && !to_plt && !is_call) { | ||
| 116 | int index; | ||
| 117 | uint8_t *p; | ||
| 118 | char *name, buf[1024]; | ||
| 119 | Section *text_section; | ||
| 120 | |||
| 121 | name = (char *) symtab_section->link->data + sym->st_name; | ||
| 122 | text_section = s1->sections[sym->st_shndx]; | ||
| 123 | /* Modify reloc to target a thumb stub to switch to ARM */ | ||
| 124 | snprintf(buf, sizeof(buf), "%s_from_thumb", name); | ||
| 125 | index = put_elf_sym(symtab_section, | ||
| 126 | text_section->data_offset + 1, | ||
| 127 | sym->st_size, sym->st_info, 0, | ||
| 128 | sym->st_shndx, buf); | ||
| 129 | to_thumb = 1; | ||
| 130 | val = text_section->data_offset + 1; | ||
| 131 | rel->r_info = ELFW(R_INFO)(index, type); | ||
| 132 | /* Create a thumb stub function to switch to ARM mode */ | ||
| 133 | put_elf_reloc(symtab_section, text_section, | ||
| 134 | text_section->data_offset + 4, R_ARM_JUMP24, | ||
| 135 | sym_index); | ||
| 136 | p = section_ptr_add(text_section, 8); | ||
| 137 | write32le(p, 0x4778); /* bx pc */ | ||
| 138 | write32le(p+2, 0x46c0); /* nop */ | ||
| 139 | write32le(p+4, 0xeafffffe); /* b $sym */ | ||
| 140 | } | ||
| 141 | |||
| 92 | /* Compute final offset */ | 142 | /* Compute final offset */ |
| 93 | if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ | 143 | if (to_plt && !is_call) /* Point to 1st instr of Thumb stub */ |
| 94 | x -= 4; | 144 | x -= 4; |
| @@ -48,6 +48,7 @@ · 47 unmodified lines | |||
| 48 | #define R_DATA_32 R_AARCH64_ABS32 | 48 | #define R_DATA_32 R_AARCH64_ABS32 |
| 49 | #define R_DATA_PTR R_AARCH64_ABS64 | 49 | #define R_DATA_PTR R_AARCH64_ABS64 |
| 50 | #define R_JMP_SLOT R_AARCH64_JUMP_SLOT | 50 | #define R_JMP_SLOT R_AARCH64_JUMP_SLOT |
| 51 | #define R_GLOB_DAT R_AARCH64_GLOB_DAT | ||
| 51 | #define R_COPY R_AARCH64_COPY | 52 | #define R_COPY R_AARCH64_COPY |
| 52 | 53 | ||
| 53 | #define ELF_START_ADDR 0x00400000 | 54 | #define ELF_START_ADDR 0x00400000 |
| @@ -1,6 +1,23 @@ | |||
| 1 | #include "tcc.h" | 1 | #include "tcc.h" |
| 2 | #define HAVE_SECTION_RELOC | 2 | #define HAVE_SECTION_RELOC |
| 3 | 3 | ||
| 4 | ST_DATA struct reloc_info relocs_info[] = { | ||
| 5 | INIT_RELOC_INFO (R_AARCH64_ABS32, 0, NO_GOTPLT_ENTRY, 0) | ||
| 6 | INIT_RELOC_INFO (R_AARCH64_ABS64, 0, NO_GOTPLT_ENTRY, 0) | ||
| 7 | INIT_RELOC_INFO (R_AARCH64_MOVW_UABS_G0_NC, 0, NO_GOTPLT_ENTRY, 0) | ||
| 8 | INIT_RELOC_INFO (R_AARCH64_MOVW_UABS_G1_NC, 0, NO_GOTPLT_ENTRY, 0) | ||
| 9 | INIT_RELOC_INFO (R_AARCH64_MOVW_UABS_G2_NC, 0, NO_GOTPLT_ENTRY, 0) | ||
| 10 | INIT_RELOC_INFO (R_AARCH64_MOVW_UABS_G3, 0, NO_GOTPLT_ENTRY, 0) | ||
| 11 | INIT_RELOC_INFO (R_AARCH64_ADR_PREL_PG_HI21, 0, NO_GOTPLT_ENTRY, 0) | ||
| 12 | INIT_RELOC_INFO (R_AARCH64_ADD_ABS_LO12_NC, 0, NO_GOTPLT_ENTRY, 0) | ||
| 13 | INIT_RELOC_INFO (R_AARCH64_JUMP26, 1, AUTO_GOTPLT_ENTRY, 1) | ||
| 14 | INIT_RELOC_INFO (R_AARCH64_CALL26, 1, AUTO_GOTPLT_ENTRY, 1) | ||
| 15 | INIT_RELOC_INFO (R_AARCH64_ADR_GOT_PAGE, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 16 | INIT_RELOC_INFO (R_AARCH64_LD64_GOT_LO12_NC, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 17 | INIT_RELOC_INFO (R_AARCH64_GLOB_DAT, 0, NO_GOTPLT_ENTRY, 0) | ||
| 18 | INIT_RELOC_INFO (R_AARCH64_JUMP_SLOT, 1, NO_GOTPLT_ENTRY, 0) | ||
| 19 | }; | ||
| 20 | |||
| 4 | void relocate_init(Section *sr) {} | 21 | void relocate_init(Section *sr) {} |
| 5 | 22 | ||
| 6 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) | 23 | void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, addr_t val) |
| @@ -51,7 +68,7 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, char *ptr, addr_t addr, add · 44 unmodified lines | |||
| 51 | /* This check must match the one in build_got_entries, testing | 68 | /* This check must match the one in build_got_entries, testing |
| 52 | if we really need a PLT slot. */ | 69 | if we really need a PLT slot. */ |
| 53 | if (sym->st_shndx == SHN_UNDEF || | 70 | if (sym->st_shndx == SHN_UNDEF || |
| 54 | s1->output_type == TCC_OUTPUT_MEMORY) | 71 | sym->st_shndx == SHN_ABS) |
| 55 | /* We've put the PLT slot offset into r_addend when generating | 72 | /* We've put the PLT slot offset into r_addend when generating |
| 56 | it, and that's what we must use as relocation value (adjusted | 73 | it, and that's what we must use as relocation value (adjusted |
| 57 | by section offset of course). */ | 74 | by section offset of course). */ |
| @@ -117,6 +117,7 @@ enum { · 116 unmodified lines | |||
| 117 | #define R_DATA_32 R_C60_32 | 117 | #define R_DATA_32 R_C60_32 |
| 118 | #define R_DATA_PTR R_C60_32 | 118 | #define R_DATA_PTR R_C60_32 |
| 119 | #define R_JMP_SLOT R_C60_JMP_SLOT | 119 | #define R_JMP_SLOT R_C60_JMP_SLOT |
| 120 | #define R_GLOB_DAT R_C60_GLOB_DAT | ||
| 120 | #define R_COPY R_C60_COPY | 121 | #define R_COPY R_C60_COPY |
| 121 | 122 | ||
| 122 | #define ELF_START_ADDR 0x00000400 | 123 | #define ELF_START_ADDR 0x00000400 |
| @@ -82,6 +82,7 @@ enum { · 81 unmodified lines | |||
| 82 | #define R_DATA_32 R_386_32 | 82 | #define R_DATA_32 R_386_32 |
| 83 | #define R_DATA_PTR R_386_32 | 83 | #define R_DATA_PTR R_386_32 |
| 84 | #define R_JMP_SLOT R_386_JMP_SLOT | 84 | #define R_JMP_SLOT R_386_JMP_SLOT |
| 85 | #define R_GLOB_DAT R_386_GLOB_DAT | ||
| 85 | #define R_COPY R_386_COPY | 86 | #define R_COPY R_386_COPY |
| 86 | 87 | ||
| 87 | #define ELF_START_ADDR 0x08048000 | 88 | #define ELF_START_ADDR 0x08048000 |
| @@ -2,6 +2,19 @@ · 1 unmodified line | |||
| 2 | #define HAVE_SECTION_RELOC | 2 | #define HAVE_SECTION_RELOC |
| 3 | 3 | ||
| 4 | static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ | 4 | static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ |
| 5 | ST_DATA struct reloc_info relocs_info[] = { | ||
| 6 | INIT_RELOC_INFO (R_386_32, 0, NO_GOTPLT_ENTRY, 0) | ||
| 7 | INIT_RELOC_INFO (R_386_PC32, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 8 | INIT_RELOC_INFO (R_386_PLT32, 1, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 9 | INIT_RELOC_INFO (R_386_GLOB_DAT, 0, NO_GOTPLT_ENTRY, 0) | ||
| 10 | INIT_RELOC_INFO (R_386_JMP_SLOT, 1, NO_GOTPLT_ENTRY, 0) | ||
| 11 | INIT_RELOC_INFO (R_386_GOTPC, 0, BUILD_GOT_ONLY, 0) | ||
| 12 | INIT_RELOC_INFO (R_386_GOTOFF, 0, BUILD_GOT_ONLY, 0) | ||
| 13 | INIT_RELOC_INFO (R_386_GOT32, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 14 | INIT_RELOC_INFO (R_386_GOT32X, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 15 | INIT_RELOC_INFO (R_386_16, 0, NO_GOTPLT_ENTRY, 0) | ||
| 16 | INIT_RELOC_INFO (R_386_PC16, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 17 | }; | ||
| 5 | 18 | ||
| 6 | void relocate_init(Section *sr) | 19 | void relocate_init(Section *sr) |
| 7 | { | 20 | { |
| @@ -1305,6 +1305,26 @@ typedef struct { · 1304 unmodified lines | |||
| 1305 | unsigned int n_value; /* value of symbol */ | 1305 | unsigned int n_value; /* value of symbol */ |
| 1306 | } Stab_Sym; | 1306 | } Stab_Sym; |
| 1307 | 1307 | ||
| 1308 | /* Wether to generate a GOT/PLT entry and when. NO_GOTPLT_ENTRY is first so | ||
| 1309 | that unknown relocation don't create a GOT or PLT entry */ | ||
| 1310 | enum gotplt_entry { | ||
| 1311 | NO_GOTPLT_ENTRY, /* never generate (eg. GLOB_DAT & JMP_SLOT relocs) */ | ||
| 1312 | BUILD_GOT_ONLY, /* only build GOT (eg. TPOFF relocs) */ | ||
| 1313 | AUTO_GOTPLT_ENTRY, /* generate if sym is UNDEF */ | ||
| 1314 | ALWAYS_GOTPLT_ENTRY /* always generate (eg. PLTOFF relocs) */ | ||
| 1315 | }; | ||
| 1316 | |||
| 1317 | /* what kind of relocation is it */ | ||
| 1318 | struct reloc_info { | ||
| 1319 | int code_reloc; /* if false, that's a data reloc */ | ||
| 1320 | int gotplt_entry; /* wether and when to create a GOT/PLT entry */ | ||
| 1321 | int pltoff_addend; /* wether to store the PLT offset in addend */ | ||
| 1322 | }; | ||
| 1323 | |||
| 1324 | #define INIT_RELOC_INFO(rtype, code_reloc, gotplt_entry, pltoff_addend) \ | ||
| 1325 | [rtype] = {code_reloc, gotplt_entry, pltoff_addend}, | ||
| 1326 | ST_DATA struct reloc_info relocs_info[]; | ||
| 1327 | |||
| 1308 | ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ | 1328 | ST_DATA Section *text_section, *data_section, *bss_section; /* predefined sections */ |
| 1309 | ST_DATA Section *cur_text_section; /* current section where function code is generated */ | 1329 | ST_DATA Section *cur_text_section; /* current section where function code is generated */ |
| 1310 | #ifdef CONFIG_TCC_ASM | 1330 | #ifdef CONFIG_TCC_ASM |
| @@ -1022,6 +1022,7 @@ ST_FUNC void build_got_entries(TCCState *s1) · 1021 unmodified lines | |||
| 1022 | ElfW_Rel *rel; | 1022 | ElfW_Rel *rel; |
| 1023 | ElfW(Sym) *sym; | 1023 | ElfW(Sym) *sym; |
| 1024 | int i, type, reloc_type, sym_index; | 1024 | int i, type, reloc_type, sym_index; |
| 1025 | unsigned long ofs; | ||
| 1025 | 1026 | ||
| 1026 | for(i = 1; i < s1->nb_sections; i++) { | 1027 | for(i = 1; i < s1->nb_sections; i++) { |
| 1027 | s = s1->sections[i]; | 1028 | s = s1->sections[i]; |
| @@ -1034,222 +1035,70 @@ ST_FUNC void build_got_entries(TCCState *s1) · 6 unmodified lines | |||
| 1034 | type = ELFW(R_TYPE)(rel->r_info); | 1035 | type = ELFW(R_TYPE)(rel->r_info); |
| 1035 | sym_index = ELFW(R_SYM)(rel->r_info); | 1036 | sym_index = ELFW(R_SYM)(rel->r_info); |
| 1036 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | 1037 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; |
| 1037 | switch(type) { | 1038 | if (relocs_info[type].gotplt_entry == NO_GOTPLT_ENTRY) |
| 1038 | #if defined(TCC_TARGET_I386) | 1039 | continue; |
| 1039 | case R_386_PC16: | ||
| 1040 | case R_386_PC32: | ||
| 1041 | case R_386_GOT32: | ||
| 1042 | case R_386_GOT32X: | ||
| 1043 | case R_386_GOTOFF: | ||
| 1044 | case R_386_GOTPC: | ||
| 1045 | case R_386_PLT32: | ||
| 1046 | if (sym->st_shndx != SHN_UNDEF && type != R_386_GOT32 && | ||
| 1047 | type != R_386_GOT32X && type != R_386_GOTOFF && | ||
| 1048 | type != R_386_GOTPC && type != R_386_PLT32) | ||
| 1049 | break; | ||
| 1050 | 1040 | ||
| 1051 | if (!s1->got) | 1041 | /* Proceed with PLT/GOT [entry] creation if any of the following |
| 1052 | build_got(s1); | 1042 | condition is met: |
| 1053 | 1043 | - it is an undefined reference (dynamic relocation needed) | |
| 1054 | if (type != R_386_GOTOFF && type != R_386_GOTPC) { | 1044 | - symbol is absolute (probably created by tcc_add_symbol) |
| 1055 | /* look at the symbol got offset. If none, then add one */ | 1045 | - relocation requires a PLT/GOT (BUILD_GOTPLT_ENTRY or |
| 1056 | if (type == R_386_GOT32 || type == R_386_GOT32X) | 1046 | ALWAYS_GOTPLT_ENTRY). */ |
| 1057 | reloc_type = R_386_GLOB_DAT; | 1047 | if (sym->st_shndx != SHN_UNDEF && |
| 1058 | else | 1048 | sym->st_shndx != SHN_ABS && |
| 1059 | reloc_type = R_386_JMP_SLOT; | 1049 | relocs_info[type].gotplt_entry == AUTO_GOTPLT_ENTRY) |
| 1060 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, | 1050 | continue; |
| 1061 | sym_index); | ||
| 1062 | } | ||
| 1063 | break; | ||
| 1064 | #elif defined(TCC_TARGET_ARM) | ||
| 1065 | case R_ARM_PC24: | ||
| 1066 | case R_ARM_CALL: | ||
| 1067 | case R_ARM_JUMP24: | ||
| 1068 | case R_ARM_PLT32: | ||
| 1069 | case R_ARM_THM_PC22: | ||
| 1070 | case R_ARM_MOVT_ABS: | ||
| 1071 | case R_ARM_MOVW_ABS_NC: | ||
| 1072 | case R_ARM_THM_MOVT_ABS: | ||
| 1073 | case R_ARM_THM_MOVW_ABS_NC: | ||
| 1074 | case R_ARM_PREL31: | ||
| 1075 | case R_ARM_REL32: | ||
| 1076 | case R_ARM_GOTPC: | ||
| 1077 | case R_ARM_GOTOFF: | ||
| 1078 | case R_ARM_GOT32: | ||
| 1079 | case R_ARM_V4BX: | ||
| 1080 | if (sym->st_shndx != SHN_UNDEF && type != R_ARM_GOT32 && | ||
| 1081 | type != R_ARM_GOTOFF && type != R_ARM_GOTPC && | ||
| 1082 | type != R_ARM_PLT32) | ||
| 1083 | break; | ||
| 1084 | 1051 | ||
| 1085 | if (!s1->got) | 1052 | #ifdef TCC_TARGET_X86_64 |
| 1086 | build_got(s1); | 1053 | if (type == R_X86_64_PLT32 && |
| 1087 | if (type != R_ARM_GOTOFF && type != R_ARM_GOTPC | 1054 | ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) { |
| 1088 | && (sym->st_shndx == SHN_UNDEF | 1055 | rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); |
| 1089 | || s1->output_type == TCC_OUTPUT_MEMORY)) { | 1056 | continue; |
| 1090 | unsigned long ofs; | 1057 | } |
| 1091 | /* look at the symbol got offset. If none, then add one */ | ||
| 1092 | if (type == R_ARM_GOT32 || type == R_ARM_MOVT_ABS || | ||
| 1093 | type == R_ARM_MOVW_ABS_NC || | ||
| 1094 | type == R_ARM_THM_MOVT_ABS || | ||
| 1095 | type == R_ARM_THM_MOVW_ABS_NC || type == R_ARM_ABS32 || | ||
| 1096 | type == R_ARM_REL32) | ||
| 1097 | reloc_type = R_ARM_GLOB_DAT; | ||
| 1098 | else | ||
| 1099 | reloc_type = R_ARM_JUMP_SLOT; | ||
| 1100 | ofs = put_got_entry(s1, reloc_type, sym->st_size, | ||
| 1101 | sym->st_info, sym_index); | ||
| 1102 | #ifdef DEBUG_RELOC | ||
| 1103 | printf ("maybegot: %s, %d, %d --> ofs=0x%x\n", | ||
| 1104 | (char *) symtab_section->link->data + sym->st_name, | ||
| 1105 | type, sym->st_shndx, ofs); | ||
| 1106 | #endif | ||
| 1107 | if (type == R_ARM_PC24 || type == R_ARM_CALL || | ||
| 1108 | type == R_ARM_JUMP24 || type == R_ARM_PLT32) { | ||
| 1109 | addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data | ||
| 1110 | + rel->r_offset); | ||
| 1111 | /* x must be signed! */ | ||
| 1112 | int x = *ptr & 0xffffff; | ||
| 1113 | x = (x << 8) >> 8; | ||
| 1114 | x <<= 2; | ||
| 1115 | x += ofs; | ||
| 1116 | x >>= 2; | ||
| 1117 | #ifdef DEBUG_RELOC | ||
| 1118 | printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr, | ||
| 1119 | (*ptr & 0xff000000) | x, x); | ||
| 1120 | #endif | 1058 | #endif |
| 1121 | *ptr = (*ptr & 0xff000000) | x; | ||
| 1122 | } | ||
| 1123 | } | ||
| 1124 | break; | ||
| 1125 | case R_ARM_THM_JUMP24: | ||
| 1126 | sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 1127 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 1128 | /* We are relocating a jump from thumb code to arm code */ | ||
| 1129 | if (sym->st_shndx != SHN_UNDEF && !(sym->st_value & 1)) { | ||
| 1130 | int index; | ||
| 1131 | uint8_t *p; | ||
| 1132 | char *name, buf[1024]; | ||
| 1133 | Section *text_section; | ||
| 1134 | |||
| 1135 | name = (char *) symtab_section->link->data + sym->st_name; | ||
| 1136 | text_section = s1->sections[sym->st_shndx]; | ||
| 1137 | /* Modify reloc to target a thumb stub to switch to ARM */ | ||
| 1138 | snprintf(buf, sizeof(buf), "%s_from_thumb", name); | ||
| 1139 | index = put_elf_sym(symtab_section, | ||
| 1140 | text_section->data_offset + 1, | ||
| 1141 | sym->st_size, sym->st_info, 0, | ||
| 1142 | sym->st_shndx, buf); | ||
| 1143 | rel->r_info = ELFW(R_INFO)(index, type); | ||
| 1144 | /* Create a thumb stub fonction to switch to ARM mode */ | ||
| 1145 | put_elf_reloc(symtab_section, text_section, | ||
| 1146 | text_section->data_offset + 4, R_ARM_JUMP24, | ||
| 1147 | sym_index); | ||
| 1148 | p = section_ptr_add(text_section, 8); | ||
| 1149 | write32le(p, 0x4778); /* bx pc */ | ||
| 1150 | write32le(p+2, 0x46c0); /* nop */ | ||
| 1151 | write32le(p+4, 0xeafffffe); /* b $sym */ | ||
| 1152 | } | ||
| 1153 | #elif defined(TCC_TARGET_ARM64) | ||
| 1154 | //xx Other cases may be required here: | ||
| 1155 | case R_AARCH64_ADR_GOT_PAGE: | ||
| 1156 | case R_AARCH64_LD64_GOT_LO12_NC: | ||
| 1157 | if (!s1->got) | ||
| 1158 | build_got(s1); | ||
| 1159 | sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 1160 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 1161 | reloc_type = R_AARCH64_GLOB_DAT; | ||
| 1162 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, | ||
| 1163 | sym_index); | ||
| 1164 | break; | ||
| 1165 | 1059 | ||
| 1166 | case R_AARCH64_JUMP26: | 1060 | if (!s1->got) |
| 1167 | case R_AARCH64_CALL26: | 1061 | build_got(s1); |
| 1168 | if (!s1->got) | ||
| 1169 | build_got(s1); | ||
| 1170 | sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 1171 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 1172 | if (sym->st_shndx == SHN_UNDEF || | ||
| 1173 | s1->output_type == TCC_OUTPUT_MEMORY) { | ||
| 1174 | unsigned long ofs; | ||
| 1175 | reloc_type = R_AARCH64_JUMP_SLOT; | ||
| 1176 | ofs = put_got_entry(s1, reloc_type, sym->st_size, | ||
| 1177 | sym->st_info, sym_index); | ||
| 1178 | /* We store the place of the generated PLT slot | ||
| 1179 | in our addend. */ | ||
| 1180 | rel->r_addend += ofs; | ||
| 1181 | } | ||
| 1182 | break; | ||
| 1183 | #elif defined(TCC_TARGET_C67) | ||
| 1184 | case R_C60_GOT32: | ||
| 1185 | case R_C60_GOTOFF: | ||
| 1186 | case R_C60_GOTPC: | ||
| 1187 | case R_C60_PLT32: | ||
| 1188 | if (!s1->got) | ||
| 1189 | build_got(s1); | ||
| 1190 | if (type == R_C60_GOT32 || type == R_C60_PLT32) { | ||
| 1191 | sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 1192 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 1193 | /* look at the symbol got offset. If none, then add one */ | ||
| 1194 | if (type == R_C60_GOT32) | ||
| 1195 | reloc_type = R_C60_GLOB_DAT; | ||
| 1196 | else | ||
| 1197 | reloc_type = R_C60_JMP_SLOT; | ||
| 1198 | put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, | ||
| 1199 | sym_index); | ||
| 1200 | } | ||
| 1201 | break; | ||
| 1202 | #elif defined(TCC_TARGET_X86_64) | ||
| 1203 | case R_X86_64_32: | ||
| 1204 | case R_X86_64_32S: | ||
| 1205 | case R_X86_64_64: | ||
| 1206 | case R_X86_64_PC32: | ||
| 1207 | case R_X86_64_GOT32: | ||
| 1208 | case R_X86_64_GOTTPOFF: | ||
| 1209 | case R_X86_64_GOTPCREL: | ||
| 1210 | case R_X86_64_GOTPCRELX: | ||
| 1211 | case R_X86_64_REX_GOTPCRELX: | ||
| 1212 | case R_X86_64_PLT32: | ||
| 1213 | sym_index = ELFW(R_SYM)(rel->r_info); | ||
| 1214 | sym = &((ElfW(Sym) *)symtab_section->data)[sym_index]; | ||
| 1215 | if ((type == R_X86_64_32 || type == R_X86_64_32S || | ||
| 1216 | type == R_X86_64_64 || type == R_X86_64_PC32) && | ||
| 1217 | sym->st_shndx != SHN_UNDEF) | ||
| 1218 | break; | ||
| 1219 | 1062 | ||
| 1220 | if (type == R_X86_64_PLT32 && | 1063 | if (relocs_info[type].gotplt_entry == BUILD_GOT_ONLY) |
| 1221 | ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT) { | 1064 | continue; |
| 1222 | rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32); | ||
| 1223 | break; | ||
| 1224 | } | ||
| 1225 | 1065 | ||
| 1226 | if (!s1->got) | 1066 | if (relocs_info[type].code_reloc) |
| 1227 | build_got(s1); | 1067 | reloc_type = R_JMP_SLOT; |
| 1228 | if (type != R_X86_64_GOTTPOFF) { | 1068 | else |
| 1229 | unsigned long ofs; | 1069 | reloc_type = R_GLOB_DAT; |
| 1230 | /* look at the symbol got offset. If none, then add one */ | 1070 | ofs = put_got_entry(s1, reloc_type, sym->st_size, sym->st_info, |
| 1231 | if (type == R_X86_64_GOT32 || type == R_X86_64_GOTPCREL || | 1071 | sym_index); |
| 1232 | type == R_X86_64_GOTPCRELX || | 1072 | |
| 1233 | type == R_X86_64_REX_GOTPCRELX || | 1073 | #ifdef DEBUG_RELOC |
| 1234 | type == R_X86_64_32 || type == R_X86_64_32S || | 1074 | printf ("maybegot: %s, %d, %d --> ofs=0x%x\n", |
| 1235 | type == R_X86_64_64) | 1075 | (char *) symtab_section->link->data + sym->st_name, type, |
| 1236 | reloc_type = R_X86_64_GLOB_DAT; | 1076 | sym->st_shndx, ofs); |
| 1237 | else | ||
| 1238 | reloc_type = R_X86_64_JUMP_SLOT; | ||
| 1239 | ofs = put_got_entry(s1, reloc_type, sym->st_size, | ||
| 1240 | sym->st_info, sym_index); | ||
| 1241 | if (type == R_X86_64_PLT32) | ||
| 1242 | /* We store the place of the generated PLT slot | ||
| 1243 | in our addend. */ | ||
| 1244 | rel->r_addend += ofs; | ||
| 1245 | } | ||
| 1246 | break; | ||
| 1247 | #else | ||
| 1248 | #error unsupported CPU | ||
| 1249 | #endif | 1077 | #endif |
| 1250 | default: | 1078 | |
| 1251 | break; | 1079 | #if defined (TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64) |
| 1080 | /* We store the place of the generated PLT slot in our addend. */ | ||
| 1081 | if (relocs_info[type].pltoff_addend) | ||
| 1082 | rel->r_addend += ofs; | ||
| 1083 | |||
| 1084 | #elif defined (TCC_TARGET_ARM) | ||
| 1085 | if (type == R_ARM_PC24 || type == R_ARM_CALL || | ||
| 1086 | type == R_ARM_JUMP24 || type == R_ARM_PLT32) { | ||
| 1087 | addr_t *ptr = (addr_t*)(s1->sections[s->sh_info]->data | ||
| 1088 | + rel->r_offset); | ||
| 1089 | /* x must be signed! */ | ||
| 1090 | int x = *ptr & 0xffffff; | ||
| 1091 | x = (x << 8) >> 8; | ||
| 1092 | x <<= 2; | ||
| 1093 | x += ofs; | ||
| 1094 | x >>= 2; | ||
| 1095 | #ifdef DEBUG_RELOC | ||
| 1096 | printf ("insn=0x%x --> 0x%x (x==0x%x)\n", *ptr, | ||
| 1097 | (*ptr & 0xff000000) | x, x); | ||
| 1098 | #endif | ||
| 1099 | *ptr = (*ptr & 0xff000000) | x; | ||
| 1252 | } | 1100 | } |
| 1101 | #endif | ||
| 1253 | } | 1102 | } |
| 1254 | } | 1103 | } |
| 1255 | } | 1104 | } |
| @@ -110,6 +110,7 @@ enum { · 109 unmodified lines | |||
| 110 | #define R_DATA_32 R_X86_64_32 | 110 | #define R_DATA_32 R_X86_64_32 |
| 111 | #define R_DATA_PTR R_X86_64_64 | 111 | #define R_DATA_PTR R_X86_64_64 |
| 112 | #define R_JMP_SLOT R_X86_64_JUMP_SLOT | 112 | #define R_JMP_SLOT R_X86_64_JUMP_SLOT |
| 113 | #define R_GLOB_DAT R_X86_64_GLOB_DAT | ||
| 113 | #define R_COPY R_X86_64_COPY | 114 | #define R_COPY R_X86_64_COPY |
| 114 | 115 | ||
| 115 | #define ELF_START_ADDR 0x400000 | 116 | #define ELF_START_ADDR 0x400000 |
| @@ -2,6 +2,20 @@ · 1 unmodified line | |||
| 2 | #define HAVE_SECTION_RELOC | 2 | #define HAVE_SECTION_RELOC |
| 3 | 3 | ||
| 4 | static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ | 4 | static ElfW_Rel *qrel; /* ptr to next reloc entry reused */ |
| 5 | ST_DATA struct reloc_info relocs_info[] = { | ||
| 6 | INIT_RELOC_INFO (R_X86_64_64, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 7 | INIT_RELOC_INFO (R_X86_64_32, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 8 | INIT_RELOC_INFO (R_X86_64_32S, 0, AUTO_GOTPLT_ENTRY, 0) | ||
| 9 | INIT_RELOC_INFO (R_X86_64_PC32, 1, AUTO_GOTPLT_ENTRY, 0) | ||
| 10 | INIT_RELOC_INFO (R_X86_64_PLT32, 1, ALWAYS_GOTPLT_ENTRY, 1) | ||
| 11 | INIT_RELOC_INFO (R_X86_64_GLOB_DAT, 0, NO_GOTPLT_ENTRY, 0) | ||
| 12 | INIT_RELOC_INFO (R_X86_64_JUMP_SLOT, 1, NO_GOTPLT_ENTRY, 0) | ||
| 13 | INIT_RELOC_INFO (R_X86_64_GOTPCREL, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 14 | INIT_RELOC_INFO (R_X86_64_GOTPCRELX, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 15 | INIT_RELOC_INFO (R_X86_64_REX_GOTPCRELX, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 16 | INIT_RELOC_INFO (R_X86_64_GOTTPOFF, 0, BUILD_GOT_ONLY, 0) | ||
| 17 | INIT_RELOC_INFO (R_X86_64_GOT32, 0, ALWAYS_GOTPLT_ENTRY, 0) | ||
| 18 | }; | ||
| 5 | 19 | ||
| 6 | void relocate_init(Section *sr) | 20 | void relocate_init(Section *sr) |
| 7 | { | 21 | { |