Fix block trampolines to work when mixed with Thumb-2 code.

main
David Chisnall 10 years ago
parent f5f60ecadd
commit 9e51aabc98

@ -109,6 +109,15 @@ static struct trampoline_set *alloc_trampolines(char *start, char *end)
{
struct trampoline_set *metadata = calloc(1, sizeof(struct trampoline_set));
metadata->buffers = valloc(sizeof(struct trampoline_buffers));
#if ((__ARM_ARCH >= 7) || defined (__ARM_ARCH_6T2__))
// If the trampoline is Thumb-2 code, then the linker will set this symbol
// to something that you can jump to with a b[l]x instruction, not to the
// actual start address. This code is safe on all supported architectures
// (as we don't have anything with 1-byte alignment requirements), but it
// is a couple of nops everywhere else, so don't bother with it.
start = (void*)((uintptr_t)start & ~1);
end = (void*)((uintptr_t)end & ~1);
#endif
for (int i=0 ; i<HEADERS_PER_PAGE ; i++)
{
metadata->buffers->headers[i].fnptr = (void(*)(void))invalid;
@ -167,7 +176,13 @@ IMP imp_implementationWithBlock(void *block)
assert(set->first_free >= -1);
h->fnptr = (void(*)(void))b->invoke;
h->block = b;
return (IMP)&set->buffers->rx_buffer[i*sizeof(struct block_header)];
uintptr_t addr = (uintptr_t)&set->buffers->rx_buffer[i*sizeof(struct block_header)];
#if ((__ARM_ARCH >= 7) || defined (__ARM_ARCH_6T2__))
// If the trampoline is Thumb-2 code, then we must set the low bit
// to 1 so that b[l]x instructions put the CPU in the correct mode.
addr |= 1;
#endif
return (IMP)addr;
}
}
UNREACHABLE("Failed to allocate block");

@ -116,17 +116,32 @@ CDECL(__objc_block_trampoline_sret):
trampoline x1, x2
CDECL(__objc_block_trampoline_end_sret):
#elif __arm__
CDECL(__objc_block_trampoline):
#if 0 && ((__ARM_ARCH >= 7) || defined (__ARM_ARCH_6T2__))
// If we're on a target that supports Thumb 2, then we need slightly more
// instructions to support Thumb/ARM code for the IMP and so we need to make
// the trampolines thumb to be able to fit them in 16 bytes (they fit exactly
// when assembled as Thumb-2).
.thumb
.macro trampoline arg0, arg1
sub r12, pc, #4095
mov \arg0, \arg1 // Move self over _cmd
ldr \arg0, [r12, #-5] // Load the block pointer over self
ldr r12, [r12, #-1] // Jump to the block function
bx r12
.endm
#else
.macro trampoline arg0, arg1
sub r12, pc, #4096
mov r1, r0 // Move self over _cmd
ldr r0, [r12, #-8] // Load the block pointer over self
ldr pc, [r12, #-4] // Jump to the block function
mov \arg0, \arg1 // Move self over _cmd
ldr \arg0, [r12, #-8] // Load the block pointer over self
ldr pc, [r12, #-4] // Jump to the block function
.endm
#endif // ((__ARM_ARCH >= 7) || defined (__ARM_ARCH_6T2__))
CDECL(__objc_block_trampoline):
trampoline r0, r1
CDECL(__objc_block_trampoline_end):
CDECL(__objc_block_trampoline_sret):
sub r12, pc, #4096
mov r2, r1 // Move self over _cmd
ldr r1, [r12, #-8] // Load the block pointer over self
ldr pc, [r12, #-4] // Jump to the block function
trampoline r1, r2
CDECL(__objc_block_trampoline_end_sret):
#else
#warning imp_implementationWithBlock() not implemented for your architecture

Loading…
Cancel
Save