Prevent RCTProfileTrampoline from getting stripped

Summary: public

I was using `dlsym` as a more elegant way of checking if the function was defined
to prevent crashes if running on an unsupported architecture, but Xcode might
strip the symbol, even with `.no_dead_strip`, if there's no references to the
compilation unit at all.

Replace it with an ugly `#if` that checks if it's any of the supported targets
and extern the function prototype.

Reviewed By: jspahrsummers

Differential Revision: D2581143

fb-gh-sync-id: b004ed351de97f96c04b4a6c914ce55cfcbbbcbb
This commit is contained in:
Tadeu Zagallo 2015-10-27 12:59:27 -07:00 committed by facebook-github-bot-6
parent 0e4dec930b
commit 0f92639a96
6 changed files with 61 additions and 39 deletions

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#define _CONCAT(A, B) A##B
#define CONCAT(A, B) _CONCAT(A, B)
#define SYMBOL_NAME(S) CONCAT(__USER_LABEL_PREFIX__, S)

View File

@ -190,16 +190,15 @@ IMP RCTProfileGetImplementation(id obj, SEL cmd)
* The implementation can be found in RCTProfileTrampoline-<arch>.s where arch
* is one of: x86, x86_64, arm, arm64.
*/
static IMP RCTProfileGetTrampoline(void)
{
static void (*RCTProfileTrampoline)(void);
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
RCTProfileTrampoline = dlsym(RTLD_DEFAULT, "RCTProfileTrampoline");
});
#if defined(__x86__) || \
defined(__x86_64__) || \
defined(__arm__) || \
defined(__arm64__)
return (IMP)RCTProfileTrampoline;
}
RCT_EXTERN void RCTProfileTrampoline(void);
#else
static void *RCTProfileTrampoline = NULL;
#endif
RCT_EXTERN void RCTProfileTrampolineStart(id, SEL);
void RCTProfileTrampolineStart(id self, SEL cmd)
@ -216,9 +215,12 @@ void RCTProfileTrampolineEnd(void)
void RCTProfileHookModules(RCTBridge *bridge)
{
if (RCTProfileGetTrampoline() == NULL) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-pointer-compare"
if (RCTProfileTrampoline == NULL) {
return;
}
#pragma clang diagnostic pop
for (RCTModuleData *moduleData in [bridge valueForKey:@"moduleDataByID"]) {
[moduleData dispatchBlock:^{
@ -239,7 +241,7 @@ void RCTProfileHookModules(RCTBridge *bridge)
}
const char *types = method_getTypeEncoding(method);
class_addMethod(proxyClass, selector, RCTProfileGetTrampoline(), types);
class_addMethod(proxyClass, selector, RCTProfileTrampoline, types);
}
free(methods);

View File

@ -1,10 +1,11 @@
#include "RCTDefines.h"
#include "RCTMacros.h"
#if RCT_DEV && defined(__arm__)
.align 5
.globl _RCTProfileTrampoline
_RCTProfileTrampoline:
.globl SYMBOL_NAME(RCTProfileTrampoline)
SYMBOL_NAME(RCTProfileTrampoline):
/**
* The explanation here is shorter, refer to the x86_64 implementation to a
* richer explanation
@ -24,7 +25,7 @@ _RCTProfileTrampoline:
* profile
*/
mov r0, #0xc
bl _malloc
bl SYMBOL_NAME(malloc)
/**
* r4 is the callee saved register we'll use to refer to the allocated memory,
* store its initial value, so we can restore it later
@ -40,7 +41,7 @@ _RCTProfileTrampoline:
*/
ldr r0, [sp]
ldr r1, [sp, #0x4]
bl _RCTProfileGetImplementation
bl SYMBOL_NAME(RCTProfileGetImplementation)
// store the actual function address in the allocated memory
str r0, [r4, #0x4]
@ -51,7 +52,7 @@ _RCTProfileTrampoline:
*/
ldr r0, [sp]
ldr r1, [sp, #0x4]
bl _RCTProfileTrampolineStart
bl SYMBOL_NAME(RCTProfileTrampolineStart)
/**
* Restore the state to call the actual function we want to profile: pop
@ -66,7 +67,7 @@ _RCTProfileTrampoline:
push {r0} // save return value
// void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
bl _RCTProfileTrampolineEnd
bl SYMBOL_NAME(RCTProfileTrampolineEnd)
/**
* Save the value we still need from the allocated memory (caller address),
@ -76,7 +77,7 @@ _RCTProfileTrampoline:
ldr r1, [r4, #0x8]
ldr r4, [r4]
push {r1} // save the caller on the stack
bl _free
bl SYMBOL_NAME(free)
pop {lr} // pop the caller
pop {r0} // pop the return value

View File

@ -1,10 +1,11 @@
#include "RCTDefines.h"
#include "RCTMacros.h"
#if RCT_DEV && defined(__arm64__)
.align 5
.globl _RCTProfileTrampoline
_RCTProfileTrampoline:
.globl SYMBOL_NAME(RCTProfileTrampoline)
SYMBOL_NAME(RCTProfileTrampoline):
/**
* The explanation here is shorter, refer to the x86_64 implementation to a
* richer explanation
@ -38,7 +39,7 @@ _RCTProfileTrampoline:
* the implementation and the caller address.
*/
mov x0, #0x10
bl _malloc
bl SYMBOL_NAME(malloc)
// store the initial value of r19, the callee saved register we'll use
str x19, [x0]
mov x19, x0
@ -50,7 +51,7 @@ _RCTProfileTrampoline:
* this function
*/
ldp x0, x1, [sp, #(8*16+0*8)]
bl _RCTProfileGetImplementation
bl SYMBOL_NAME(RCTProfileGetImplementation)
str x0, [x19, #0x8] // store the actual function address
/**
@ -59,7 +60,7 @@ _RCTProfileTrampoline:
* start the profile, it takes the same first 2 arguments as above.
*/
ldp x0, x1, [sp, #(8*16+0*8)]
bl _RCTProfileTrampolineStart
bl SYMBOL_NAME(RCTProfileTrampolineStart)
// Restore all the parameter registers to the initial state.
ldp q0, q1, [sp, #(0*16)]
@ -91,7 +92,7 @@ _RCTProfileTrampoline:
str x0, [sp, #0x10] // 8-byte return value
// void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
bl _RCTProfileTrampolineEnd
bl SYMBOL_NAME(RCTProfileTrampolineEnd)
/**
* restore the callee saved registers, move the values we still need to the
@ -101,7 +102,7 @@ _RCTProfileTrampoline:
ldr x10, [x19, #0x8] // load the caller address
ldr x19, [x19] // restore x19
str x10, [sp, #0x18] // store x10 on the stack space allocated above
bl _free
bl SYMBOL_NAME(free)
// Load both return values and link register from the stack
ldr q0, [sp, #0x0]

View File

@ -1,9 +1,10 @@
#include "RCTDefines.h"
#include "RCTMacros.h"
#if RCT_DEV && defined(__i386__)
.globl _RCTProfileTrampoline
_RCTProfileTrampoline:
.globl SYMBOL_NAME(RCTProfileTrampoline)
SYMBOL_NAME(RCTProfileTrampoline):
/**
* The x86 version is much simpler, since all the arguments are passed in the
* stack, so we just have to preserve the stack pointer (%esp) and the callee
@ -20,7 +21,7 @@ _RCTProfileTrampoline:
*/
subl $0x8, %esp // stack padding (16-byte alignment for function calls)
pushl $0xc // allocate 12-bytes
calll _malloc
calll SYMBOL_NAME(malloc)
addl $0xc, %esp // restore stack (8-byte padding + 4-byte argument)
/**
@ -37,7 +38,7 @@ _RCTProfileTrampoline:
*
* Get the address of the actual C function we have to profile
*/
calll _RCTProfileGetImplementation
calll SYMBOL_NAME(RCTProfileGetImplementation)
movl %eax, 0x8(%edi) // Save it in the allocated memory
/**
@ -47,7 +48,7 @@ _RCTProfileTrampoline:
* stack since it takes the same first 2 arguments as the any ObjC function -
* "self" and "_cmd"
*/
calll _RCTProfileTrampolineStart
calll SYMBOL_NAME(RCTProfileTrampolineStart)
/**
* Call the actual function and save it's return value, since it should be the
@ -58,7 +59,7 @@ _RCTProfileTrampoline:
// Align stack and end profile
subl $0xc, %esp
calll _RCTProfileTrampolineEnd
calll SYMBOL_NAME(RCTProfileTrampolineEnd)
addl $0xc, %esp // restore the stack
/**
@ -75,7 +76,7 @@ _RCTProfileTrampoline:
* the stack has already been padded and the first and only argument, the
* memory address, is already in the bottom of the stack.
*/
calll _free
calll SYMBOL_NAME(free)
addl $0x8, %esp
/**

View File

@ -1,9 +1,13 @@
#include "RCTDefines.h"
#include "RCTMacros.h"
#if RCT_DEV && defined(__x86_64__)
.globl _RCTProfileTrampoline
_RCTProfileTrampoline:
/**
* Define both symbols for compatibility with other assemblers
*/
.globl SYMBOL_NAME(RCTProfileTrampoline)
SYMBOL_NAME(RCTProfileTrampoline):
/**
* Saves all the state so we can restore it before calling the functions being
@ -40,7 +44,7 @@ _RCTProfileTrampoline:
* This is a C function defined in `RCTProfile.m`, the object and the selector
* already have to be on %rdi and %rsi respectively, as in any ObjC call.
*/
callq _RCTProfileGetImplementation
callq SYMBOL_NAME(RCTProfileGetImplementation)
// Restore/unalign the stack pointer, so we can access the registers we stored
movq %r12, %rsp
@ -71,7 +75,7 @@ _RCTProfileTrampoline:
// allocate 16 bytes
movq $0x10, %rdi
callq _malloc
callq SYMBOL_NAME(malloc)
// store the initial value of calle saved registers %r13 and %r14
movq %r13, 0x0(%rax)
@ -89,7 +93,7 @@ _RCTProfileTrampoline:
movq 0x38(%r12), %rsi // selector
// void RCTProfileTrampolineStart(id, SEL) in RCTProfile.m
callq _RCTProfileTrampolineStart
callq SYMBOL_NAME(RCTProfileTrampolineStart)
// unalign the stack and restore %r12
movq %r12, %rsp
@ -121,7 +125,7 @@ _RCTProfileTrampoline:
andq $-0x10, %rsp
// void RCTProfileTrampolineEnd(void) in RCTProfile.m - just ends this profile
callq _RCTProfileTrampolineEnd
callq SYMBOL_NAME(RCTProfileTrampolineEnd)
// unalign stack and restore %r12
movq %r12, %rsp
@ -151,7 +155,7 @@ _RCTProfileTrampoline:
// Free the memory allocated to stash callee saved registers
movq %rdx, %rdi
callq _free
callq SYMBOL_NAME(free)
// unalign stack and restore %r12
movq %r12, %rsp