@@ -199,17 +199,46 @@ class ARMV5LongLdrPcThunk final : public ARMThunk {
199
199
void addSymbols (ThunkSection &isec) override ;
200
200
};
201
201
202
+ // Implementations of Thunks for v4. BLX is not supported, and loads
203
+ // will not invoke Arm/Thumb state changes.
204
+ class ARMV4PILongBXThunk final : public ARMThunk {
205
+ public:
206
+ ARMV4PILongBXThunk (Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
207
+
208
+ uint32_t sizeLong () override { return 16 ; }
209
+ void writeLong (uint8_t *buf) override ;
210
+ void addSymbols (ThunkSection &isec) override ;
211
+ };
212
+
202
213
class ARMV4PILongThunk final : public ARMThunk {
203
214
public:
204
215
ARMV4PILongThunk (Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
205
216
217
+ uint32_t sizeLong () override { return 12 ; }
218
+ void writeLong (uint8_t *buf) override ;
219
+ void addSymbols (ThunkSection &isec) override ;
220
+ };
221
+
222
+ class ThumbV4PILongBXThunk final : public ThumbThunk {
223
+ public:
224
+ ThumbV4PILongBXThunk (Symbol &dest, int64_t addend)
225
+ : ThumbThunk(dest, addend) {}
226
+
206
227
uint32_t sizeLong () override { return 16 ; }
207
228
void writeLong (uint8_t *buf) override ;
208
229
void addSymbols (ThunkSection &isec) override ;
209
230
};
210
231
211
- // Implementations of Thunks for v4. BLX is not supported, and loads
212
- // will not invoke Arm/Thumb state changes.
232
+ class ThumbV4PILongThunk final : public ThumbThunk {
233
+ public:
234
+ ThumbV4PILongThunk (Symbol &dest, int64_t addend)
235
+ : ThumbThunk(dest, addend) {}
236
+
237
+ uint32_t sizeLong () override { return 20 ; }
238
+ void writeLong (uint8_t *buf) override ;
239
+ void addSymbols (ThunkSection &isec) override ;
240
+ };
241
+
213
242
class ARMV4ABSLongBXThunk final : public ARMThunk {
214
243
public:
215
244
ARMV4ABSLongBXThunk (Symbol &dest, int64_t addend) : ARMThunk(dest, addend) {}
@@ -788,7 +817,7 @@ void ThumbV4ABSLongThunk::addSymbols(ThunkSection &isec) {
788
817
addSymbol (" $d" , STT_NOTYPE, 12 , isec);
789
818
}
790
819
791
- void ARMV4PILongThunk ::writeLong (uint8_t *buf) {
820
+ void ARMV4PILongBXThunk ::writeLong (uint8_t *buf) {
792
821
const uint8_t data[] = {
793
822
0x04 , 0xc0 , 0x9f , 0xe5 , // P: ldr ip, [pc,#4] ; L2
794
823
0x0c , 0xc0 , 0x8f , 0xe0 , // L1: add ip, pc, ip
@@ -801,13 +830,77 @@ void ARMV4PILongThunk::writeLong(uint8_t *buf) {
801
830
target->relocateNoSym (buf + 12 , R_ARM_REL32, s - p - 12 );
802
831
}
803
832
833
+ void ARMV4PILongBXThunk::addSymbols (ThunkSection &isec) {
834
+ addSymbol (saver ().save (" __ARMv4PILongBXThunk_" + destination.getName ()),
835
+ STT_FUNC, 0 , isec);
836
+ addSymbol (" $a" , STT_NOTYPE, 0 , isec);
837
+ addSymbol (" $d" , STT_NOTYPE, 12 , isec);
838
+ }
839
+
840
+ void ARMV4PILongThunk::writeLong (uint8_t *buf) {
841
+ const uint8_t data[] = {
842
+ 0x00 , 0xc0 , 0x9f , 0xe5 , // P: ldr ip, [pc] ; L2
843
+ 0x0c , 0xf0 , 0x8f , 0xe0 , // L1: add pc, pc, r12
844
+ 0x00 , 0x00 , 0x00 , 0x00 , // L2: .word S - (P + (L1 - P) + 8)
845
+ };
846
+ uint64_t s = getARMThunkDestVA (destination);
847
+ uint64_t p = getThunkTargetSym ()->getVA () & ~0x1 ;
848
+ memcpy (buf, data, sizeof (data));
849
+ target->relocateNoSym (buf + 8 , R_ARM_REL32, s - p - 12 );
850
+ }
851
+
804
852
void ARMV4PILongThunk::addSymbols (ThunkSection &isec) {
805
853
addSymbol (saver ().save (" __ARMv4PILongThunk_" + destination.getName ()),
806
854
STT_FUNC, 0 , isec);
807
855
addSymbol (" $a" , STT_NOTYPE, 0 , isec);
856
+ addSymbol (" $d" , STT_NOTYPE, 8 , isec);
857
+ }
858
+
859
+ void ThumbV4PILongBXThunk::writeLong (uint8_t *buf) {
860
+ const uint8_t data[] = {
861
+ 0x78 , 0x47 , // P: bx pc
862
+ 0xfd , 0xe7 , // b #-6 ; Arm recommended sequence to follow bx pc
863
+ 0x00 , 0xc0 , 0x9f , 0xe5 , // ldr r12, [pc] ; L2
864
+ 0x0f , 0xf0 , 0x8c , 0xe0 , // L1: add pc, r12, pc
865
+ 0x00 , 0x00 , 0x00 , 0x00 , // L2: .word S - (P + (L1 - P) + 8)
866
+ };
867
+ uint64_t s = getARMThunkDestVA (destination);
868
+ uint64_t p = getThunkTargetSym ()->getVA () & ~0x1 ;
869
+ memcpy (buf, data, sizeof (data));
870
+ target->relocateNoSym (buf + 12 , R_ARM_REL32, s - p - 16 );
871
+ }
872
+
873
+ void ThumbV4PILongBXThunk::addSymbols (ThunkSection &isec) {
874
+ addSymbol (saver ().save (" __Thumbv4PILongBXThunk_" + destination.getName ()),
875
+ STT_FUNC, 1 , isec);
876
+ addSymbol (" $t" , STT_NOTYPE, 0 , isec);
877
+ addSymbol (" $a" , STT_NOTYPE, 4 , isec);
808
878
addSymbol (" $d" , STT_NOTYPE, 12 , isec);
809
879
}
810
880
881
+ void ThumbV4PILongThunk::writeLong (uint8_t *buf) {
882
+ const uint8_t data[] = {
883
+ 0x78 , 0x47 , // P: bx pc
884
+ 0xfd , 0xe7 , // b #-6 ; Arm recommended sequence to follow bx pc
885
+ 0x04 , 0xc0 , 0x9f , 0xe5 , // ldr ip, [pc,#4] ; L2
886
+ 0x0c , 0xc0 , 0x8f , 0xe0 , // L1: add ip, pc, ip
887
+ 0x1c , 0xff , 0x2f , 0xe1 , // bx ip
888
+ 0x00 , 0x00 , 0x00 , 0x00 , // L2: .word S - (P + (L1 - P) + 8)
889
+ };
890
+ uint64_t s = getARMThunkDestVA (destination);
891
+ uint64_t p = getThunkTargetSym ()->getVA () & ~0x1 ;
892
+ memcpy (buf, data, sizeof (data));
893
+ target->relocateNoSym (buf + 16 , R_ARM_REL32, s - p - 16 );
894
+ }
895
+
896
+ void ThumbV4PILongThunk::addSymbols (ThunkSection &isec) {
897
+ addSymbol (saver ().save (" __Thumbv4PILongThunk_" + destination.getName ()),
898
+ STT_FUNC, 1 , isec);
899
+ addSymbol (" $t" , STT_NOTYPE, 0 , isec);
900
+ addSymbol (" $a" , STT_NOTYPE, 4 , isec);
901
+ addSymbol (" $d" , STT_NOTYPE, 16 , isec);
902
+ }
903
+
811
904
// Write MIPS LA25 thunk code to call PIC function from the non-PIC one.
812
905
void MipsThunk::writeTo (uint8_t *buf) {
813
906
uint64_t s = destination.getVA ();
@@ -1143,8 +1236,6 @@ static Thunk *addThunkAArch64(RelType type, Symbol &s, int64_t a) {
1143
1236
// - MOVT and MOVW instructions cannot be used.
1144
1237
// - We can't rewrite BL in place to BLX. We will need thunks.
1145
1238
//
1146
- // TODO: Support PIC interworking thunks for V4T.
1147
- // TODO: More efficient PIC non-interworking thunks for V4T.
1148
1239
// TODO: use B for short Thumb->Arm thunks instead of LDR (this doesn't work for
1149
1240
// Arm->Thumb, as in Arm state no BX PC trick; it doesn't switch state).
1150
1241
static Thunk *addThunkArmv4 (RelType reloc, Symbol &s, int64_t a) {
@@ -1155,17 +1246,20 @@ static Thunk *addThunkArmv4(RelType reloc, Symbol &s, int64_t a) {
1155
1246
case R_ARM_PLT32:
1156
1247
case R_ARM_JUMP24:
1157
1248
case R_ARM_CALL:
1158
- if (config->picThunk )
1159
- // can be used for both Arm->Arm and Arm->Thumb
1249
+ if (config->picThunk ) {
1250
+ if (thumb_target)
1251
+ return make<ARMV4PILongBXThunk>(s, a);
1160
1252
return make<ARMV4PILongThunk>(s, a);
1253
+ }
1161
1254
if (thumb_target)
1162
1255
return make<ARMV4ABSLongBXThunk>(s, a);
1163
1256
return make<ARMV5LongLdrPcThunk>(s, a);
1164
1257
case R_ARM_THM_CALL:
1165
- if (config->picThunk && !thumb_target)
1166
- fatal (" PIC relocations across state change not supported for Armv4T" );
1167
- if (config->picThunk && thumb_target)
1168
- return make<ThumbV6MPILongThunk>(s, a);
1258
+ if (config->picThunk ) {
1259
+ if (thumb_target)
1260
+ return make<ThumbV4PILongThunk>(s, a);
1261
+ return make<ThumbV4PILongBXThunk>(s, a);
1262
+ }
1169
1263
if (thumb_target)
1170
1264
return make<ThumbV4ABSLongThunk>(s, a);
1171
1265
return make<ThumbV4ABSLongBXThunk>(s, a);
@@ -1187,7 +1281,7 @@ static Thunk *addThunkArmv5v6(RelType reloc, Symbol &s, int64_t a) {
1187
1281
case R_ARM_CALL:
1188
1282
case R_ARM_THM_CALL:
1189
1283
if (config->picThunk )
1190
- return make<ARMV4PILongThunk >(s, a);
1284
+ return make<ARMV4PILongBXThunk >(s, a);
1191
1285
return make<ARMV5LongLdrPcThunk>(s, a);
1192
1286
}
1193
1287
fatal (" relocation " + toString (reloc) + " to " + toString (s) +
0 commit comments