зеркало из https://github.com/mozilla/gecko-dev.git
checking in changes from Stefan Hanske <sh990154@mail.uni-greifswald.de> (who wrote the original version of the Linux ARM code)
This commit is contained in:
Родитель
62bffdd26e
Коммит
5d23e29da9
|
@ -93,6 +93,7 @@ endif
|
||||||
ifeq ($(OS_ARCH),Linux)
|
ifeq ($(OS_ARCH),Linux)
|
||||||
ifneq (,$(filter arm32 armv4l sa110,$(OS_TEST)))
|
ifneq (,$(filter arm32 armv4l sa110,$(OS_TEST)))
|
||||||
CPPSRCS := xptcinvoke_arm.cpp xptcstubs_arm.cpp
|
CPPSRCS := xptcinvoke_arm.cpp xptcstubs_arm.cpp
|
||||||
|
OS_CXXFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
#
|
#
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
|
|
||||||
#include "xptcprivate.h"
|
#include "xptcprivate.h"
|
||||||
|
|
||||||
#if !defined(LINUX) || !defined(__arm)
|
#if !defined(LINUX) || !defined(__arm__)
|
||||||
#error "this code is for Linux ARM only"
|
#error "This code is for Linux ARM only. Check that it works on your system, too.\nBeware that this code is highly compiler dependent."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Remember that these 'words' are 32bit DWORDS
|
// Remember that these 'words' are 32bit DWORDS
|
||||||
|
@ -135,37 +135,62 @@ XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
|
||||||
my_params.fn_copy = (PRUint32) &invoke_copy_to_stack;
|
my_params.fn_copy = (PRUint32) &invoke_copy_to_stack;
|
||||||
my_params.fn_count = (PRUint32) &invoke_count_words;
|
my_params.fn_count = (PRUint32) &invoke_count_words;
|
||||||
|
|
||||||
|
/* This is to call a given method of class that.
|
||||||
|
* The parameters are in params, the number is in paramCount.
|
||||||
|
* The routine will issue calls to count the number of words
|
||||||
|
* required for argument passing and to copy the arguments to
|
||||||
|
* the stack.
|
||||||
|
* Since APCS passes the first 3 params in r1-r3, we need to
|
||||||
|
* load the first three words from the stack and correct the stack
|
||||||
|
* pointer (sp) in the appropriate way. This means:
|
||||||
|
*
|
||||||
|
* 1.) more than 3 arguments: load r1-r3, correct sp and remember No.
|
||||||
|
* of bytes left on the stack in r4
|
||||||
|
*
|
||||||
|
* 2.) <= 2 args: load r1-r3 (we won't be causing a stack overflow I hope),
|
||||||
|
* restore sp as if nothing had happened and set the marker r4 to zero.
|
||||||
|
*
|
||||||
|
* Afterwards sp will be restored using the value in r4 (which is not a temporary register
|
||||||
|
* and will be preserved by the function/method called according to APCS [ARM Procedure
|
||||||
|
* Calling Standard]).
|
||||||
|
*
|
||||||
|
* !!! IMPORTANT !!!
|
||||||
|
* This routine makes assumptions about the vtable layout of the c++ compiler. It's implemented
|
||||||
|
* for arm-linux GNU g++ >= 2.8.1 (including egcs and gcc-2.95.[1-3])!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
__asm__ __volatile__(
|
__asm__ __volatile__(
|
||||||
"ldr r1, [%1, #12] \n\t"
|
"ldr r1, [%1, #12] \n\t" /* prepare to call invoke_count_words */
|
||||||
"ldr ip, [%1, #16] \n\t"
|
"ldr ip, [%1, #16] \n\t" /* r0=paramCount, r1=params */
|
||||||
"ldr r0, [%1, #8] \n\t"
|
"ldr r0, [%1, #8] \n\t"
|
||||||
"mov lr, pc \n\t"
|
"mov lr, pc \n\t" /* call it... */
|
||||||
"mov pc, ip \n\t"
|
"mov pc, ip \n\t"
|
||||||
"mov r4, r0, lsl #2 \n\t"
|
"mov r4, r0, lsl #2 \n\t" /* This is the amount of bytes needed. */
|
||||||
"sub sp, sp, r4 \n\t"
|
"sub sp, sp, r4 \n\t" /* use stack space for the args... */
|
||||||
"mov r0, sp \n\t"
|
"mov r0, sp \n\t" /* prepare a pointer an the stack */
|
||||||
"ldr r1, [%1, #8] \n\t"
|
"ldr r1, [%1, #8] \n\t" /* =paramCount */
|
||||||
"ldr r2, [%1, #12] \n\t"
|
"ldr r2, [%1, #12] \n\t" /* =params */
|
||||||
"ldr ip, [%1, #20] \n\t"
|
"ldr ip, [%1, #20] \n\t" /* =invoke_copy_to_stack */
|
||||||
"mov lr, pc \n\t"
|
"mov lr, pc \n\t" /* copy args to the stack like the */
|
||||||
"mov pc, ip \n\t"
|
"mov pc, ip \n\t" /* compiler would. */
|
||||||
"ldr r0, [%1] \n\t"
|
"ldr r0, [%1] \n\t" /* =that */
|
||||||
"ldr r1, [r0, #0] \n\t"
|
"ldr r1, [r0, #0] \n\t" /* get that->vtable offset */
|
||||||
"ldr r2, [%1, #4] \n\t"
|
"ldr r2, [%1, #4] \n\t"
|
||||||
"mov r2, r2, lsl #2 \n\t"
|
"mov r2, r2, lsl #2 \n\t" /* a vtable_entry(x)=8 + (4 bytes * x) */
|
||||||
"add r2, r2, #8 \n\t"
|
"add r2, r2, #8 \n\t" /* with this compilers */
|
||||||
"ldr ip, [r1, r2] \n\t"
|
"ldr ip, [r1, r2] \n\t" /* get method adress from vtable */
|
||||||
"cmp r4, #12 \n\t"
|
"cmp r4, #12 \n\t" /* more than 3 arguments??? */
|
||||||
"ldmgtia sp!, {r1, r2, r3}\n\t"
|
"ldmgtia sp!, {r1, r2, r3}\n\t" /* yes: load arguments for r1-r3 */
|
||||||
"subgt r4, r4, #12 \n\t"
|
"subgt r4, r4, #12 \n\t" /* and correct the stack pointer */
|
||||||
"ldmleia sp, {r1, r2, r3}\n\t"
|
"ldmleia sp, {r1, r2, r3}\n\t" /* no: load r1-r3 from stack */
|
||||||
"addle sp, sp, r4 \n\t"
|
"addle sp, sp, r4 \n\t" /* and restore stack pointer */
|
||||||
"movle r4, #0 \n\t"
|
"movle r4, #0 \n\t" /* a mark for restoring sp */
|
||||||
"ldr r0, [%1, #0] \n\t"
|
"ldr r0, [%1, #0] \n\t" /* get (self) */
|
||||||
"mov lr, pc \n\t"
|
"mov lr, pc \n\t" /* call mathod */
|
||||||
"mov pc, ip \n\t"
|
"mov pc, ip \n\t"
|
||||||
"add sp, sp, r4 \n\t"
|
"add sp, sp, r4 \n\t" /* restore stack pointer */
|
||||||
"mov %0, r0 \n\t"
|
"mov %0, r0 \n\t" /* the result... */
|
||||||
: "=r" (result)
|
: "=r" (result)
|
||||||
: "r" (&my_params)
|
: "r" (&my_params)
|
||||||
: "r0", "r1", "r2", "r3", "r4", "ip", "lr"
|
: "r0", "r1", "r2", "r3", "r4", "ip", "lr"
|
||||||
|
|
|
@ -24,8 +24,8 @@
|
||||||
|
|
||||||
#include "xptcprivate.h"
|
#include "xptcprivate.h"
|
||||||
|
|
||||||
#if !defined(LINUX) || !defined(__arm)
|
#if !defined(LINUX) || !defined(__arm__)
|
||||||
#error "this code is for Linux ARM only"
|
#error "This code is for Linux ARM only. Please check if it works for you, too.\nDepends strongly on gcc behaviour."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static nsresult
|
static nsresult
|
||||||
|
@ -102,37 +102,64 @@ PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The easiest way to implement this is to do it as a c++ method. This means that
|
||||||
|
* the compiler will same some registers to the stack as soon as this method is
|
||||||
|
* entered. We have to be aware of that and have to know the number of registers
|
||||||
|
* that will be pushed to the stack for now.
|
||||||
|
* The compiler passes arguments to functions/methods in r1-r3 and the rest is on the
|
||||||
|
* stack. r0 is (self).
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* !!! IMPORTANT !!!
|
||||||
|
* This code will *not* work if compiled without optimization (-O / -O2) because
|
||||||
|
* the compiler overwrites the registers r0-r3 (it thinks it's called without
|
||||||
|
* parameters) and perhaps reserves more stack space than we think.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Since we don't know the number of parameters we have to pass to the required
|
||||||
|
* method we use the following scheme:
|
||||||
|
* 1.) Save method parameters that are passed in r1-r3 to a secure location
|
||||||
|
* 2.) copy the stack space that is reserved at method entry to a secure location
|
||||||
|
* 3.) copy the method arguments that formerly where in r1-r3 right in front of the
|
||||||
|
* other arguments (if any). PrepareAndDispatch needs all arguments in an array.
|
||||||
|
* It will sort out the correct argument passing convention using the InterfaceInfo's.
|
||||||
|
* 4.) Call PrepareAndDispatch
|
||||||
|
* 5.) Copy the stack contents from our method entry back in place to exit cleanly.
|
||||||
|
*
|
||||||
|
* The easier way would be to completly implement this in assembler. This way one could get rid
|
||||||
|
* of the compiler generated function prologue.
|
||||||
|
|
||||||
#define STUB_ENTRY(n) \
|
#define STUB_ENTRY(n) \
|
||||||
nsresult nsXPTCStubBase::Stub##n() \
|
nsresult nsXPTCStubBase::Stub##n() \
|
||||||
{ \
|
{ \
|
||||||
register void* method = &PrepareAndDispatch; \
|
|
||||||
register nsresult result; \
|
register nsresult result; \
|
||||||
__asm__ __volatile__( \
|
__asm__ __volatile__( \
|
||||||
"sub sp, sp, #32 \n\t" /* correct stack for pushing all args */ \
|
"sub sp, sp, #32 \n\t" /* correct stack for pushing all args */ \
|
||||||
"str r1, [sp] \n\t" /* push all args in r1-r3 to stack */ \
|
"str r1, [sp] \n\t" /* push all args in r1-r3 to stack */ \
|
||||||
"str r2, [sp, #4] \n\t" /* to make a PRUint32 array of */ \
|
"str r2, [sp, #4] \n\t" /* */ \
|
||||||
"str r3, [sp, #8] \n\t" /* functin parameters */ \
|
"str r3, [sp, #8] \n\t" /* */ \
|
||||||
"add r1, sp, #32 \n\t" /* copy saved registers: */ \
|
"add r1, sp, #32 \n\t" /* copy saved registers: */ \
|
||||||
"ldr r2, [r1] \n\t" /* The scene is as follows - */ \
|
"ldr r2, [r1] \n\t" /* The scene is as follows - */ \
|
||||||
"str r2, [sp, #12] \n\t" /* sl, fp, ip, lr, pc get saved to the */ \
|
"str r2, [sp, #12] \n\t" /* sl, fp, ip, lr, pc get saved to the */ \
|
||||||
"ldr r2, [r1, # 4] \n\t" /* stack, and behind that is the rest */ \
|
"ldr r2, [r1, # 4] \n\t" /* stack, and behind that is the rest */ \
|
||||||
"str r2, [sp, #16] \n\t" /* of our function parameters. */ \
|
"str r2, [sp, #16] \n\t" /* of our function parameters. */ \
|
||||||
"ldr r2, [r1, # 8] \n\t" /* So we make some room and copy r1-r3 */ \
|
"ldr r2, [r1, # 8] \n\t" /* */ \
|
||||||
"str r2, [sp, #20] \n\t" /* right in place. */ \
|
"str r2, [sp, #20] \n\t" /* */ \
|
||||||
"ldr r2, [r1, #12] \n\t" \
|
"ldr r2, [r1, #12] \n\t" \
|
||||||
"str r2, [sp, #24] \n\t" \
|
"str r2, [sp, #24] \n\t" \
|
||||||
"ldr r2, [r1, #16] \n\t" \
|
"ldr r2, [r1, #16] \n\t" \
|
||||||
"str r2, [sp, #28] \n\t" \
|
"str r2, [sp, #28] \n\t" \
|
||||||
"ldmia sp, {r1, r2, r3}\n\t" \
|
"ldmia sp, {r1, r2, r3}\n\t" /* Copy method arguments to the right */ \
|
||||||
"add lr, sp, #40 \n\t" \
|
"add lr, sp, #40 \n\t" /* location. */ \
|
||||||
"stmia lr, {r1, r2, r3}\n\t" \
|
"stmia lr, {r1, r2, r3}\n\t" \
|
||||||
"add sp, sp, #12 \n\t" \
|
"add sp, sp, #12 \n\t" \
|
||||||
"mov r1, #"#n" \n\t" /* methodIndex */ \
|
"mov r1, #"#n" \n\t" /* = methodIndex */ \
|
||||||
"mov r2, lr \n\t" /* &args */ \
|
"mov r2, lr \n\t" /* = &(args) */ \
|
||||||
"bl PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi \n\t" /*PrepareAndDispatch*/ \
|
"bl PrepareAndDispatch__FP14nsXPTCStubBaseUiPUi \n\t" /*PrepareAndDispatch*/ \
|
||||||
"mov %0, r0 \n\t" /* Result */ \
|
"mov %0, r0 \n\t" /* Result */ \
|
||||||
"add r0, sp, #20 \n\t" \
|
"add r0, sp, #20 \n\t" /* copy everything back in place for */ \
|
||||||
"ldmia sp!, {r1,r2,r3} \n\t" \
|
"ldmia sp!, {r1,r2,r3} \n\t" /* the normal c++ m,ethod exit */ \
|
||||||
"stmia r0!, {r1,r2,r3} \n\t" \
|
"stmia r0!, {r1,r2,r3} \n\t" \
|
||||||
"ldmia sp!, {r1, r2} \n\t" \
|
"ldmia sp!, {r1, r2} \n\t" \
|
||||||
"stmia r0, {r1, r2} \n\t" \
|
"stmia r0, {r1, r2} \n\t" \
|
||||||
|
|
Загрузка…
Ссылка в новой задаче