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:
jband%netscape.com 2000-04-23 21:14:11 +00:00
Родитель 62bffdd26e
Коммит 5d23e29da9
3 изменённых файлов: 94 добавлений и 41 удалений

Просмотреть файл

@ -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" \