Add OpenRISC support
This patch adds support for the OpenRISC architecture. (http://opencores.org/or1k/Main_Page) This patch has been tested under Linux with QEMU-user emulation support. - 32 Bit - big endian - delayed instructions This is the only available configuration under Linux. The description of the ABI can be found on the official website. Is passes the testsuite except of the unwindtest_ffi_call.cc testcase, which seems to be a problem of gcc and not libffi. Some testcases of the gcc testsuite still fail. Signed-off-by: Sebastian Macke <sebastian@macke.de>
This commit is contained in:
@@ -24,6 +24,7 @@ EXTRA_DIST = LICENSE ChangeLog.v1 ChangeLog.libgcj \
|
||||
src/microblaze/ffi.c src/microblaze/sysv.S \
|
||||
src/microblaze/ffitarget.h \
|
||||
src/nios2/ffi.c src/nios2/ffitarget.h src/nios2/sysv.S \
|
||||
src/or1k/ffi.c src/or1k/ffitarget.h src/or1k/sysv.S \
|
||||
src/powerpc/ffi.c src/powerpc/ffi_powerpc.h \
|
||||
src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c \
|
||||
src/powerpc/sysv.S src/powerpc/linux64.S \
|
||||
@@ -169,6 +170,9 @@ endif
|
||||
if NIOS2
|
||||
nodist_libffi_la_SOURCES += src/nios2/sysv.S src/nios2/ffi.c
|
||||
endif
|
||||
if OR1K
|
||||
nodist_libffi_la_SOURCES += src/or1k/sysv.S src/or1k/ffi.c
|
||||
endif
|
||||
if POWERPC
|
||||
nodist_libffi_la_SOURCES += src/powerpc/ffi.c src/powerpc/ffi_sysv.c src/powerpc/ffi_linux64.c src/powerpc/sysv.S src/powerpc/ppc_closure.S src/powerpc/linux64.S src/powerpc/linux64_closure.S
|
||||
endif
|
||||
|
||||
1
README
1
README
@@ -74,6 +74,7 @@ tested:
|
||||
| MIPS64 | Linux | GCC |
|
||||
| Moxie | Bare metal | GCC |
|
||||
| Nios II | Linux | GCC |
|
||||
| OpenRISC | Linux | GCC |
|
||||
| PowerPC 32-bit | AIX | IBM XL C |
|
||||
| PowerPC 64-bit | AIX | IBM XL C |
|
||||
| PowerPC | AMIGA | GCC |
|
||||
|
||||
@@ -230,6 +230,10 @@ case "$host" in
|
||||
TARGET=NIOS2; TARGETDIR=nios2
|
||||
;;
|
||||
|
||||
or1k*-linux*)
|
||||
TARGET=OR1K; TARGETDIR=or1k
|
||||
;;
|
||||
|
||||
powerpc*-*-linux* | powerpc-*-sysv*)
|
||||
TARGET=POWERPC; TARGETDIR=powerpc
|
||||
HAVE_LONG_DOUBLE_VARIANT=1
|
||||
@@ -312,6 +316,7 @@ AM_CONDITIONAL(MICROBLAZE, test x$TARGET = xMICROBLAZE)
|
||||
AM_CONDITIONAL(METAG, test x$TARGET = xMETAG)
|
||||
AM_CONDITIONAL(MOXIE, test x$TARGET = xMOXIE)
|
||||
AM_CONDITIONAL(NIOS2, test x$TARGET = xNIOS2)
|
||||
AM_CONDITIONAL(OR1K, test x$TARGET = xOR1K)
|
||||
AM_CONDITIONAL(POWERPC, test x$TARGET = xPOWERPC)
|
||||
AM_CONDITIONAL(POWERPC_AIX, test x$TARGET = xPOWERPC_AIX)
|
||||
AM_CONDITIONAL(POWERPC_DARWIN, test x$TARGET = xPOWERPC_DARWIN)
|
||||
|
||||
328
src/or1k/ffi.c
Normal file
328
src/or1k/ffi.c
Normal file
@@ -0,0 +1,328 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
|
||||
|
||||
OpenRISC Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#include <ffi.h>
|
||||
#include "ffi_common.h"
|
||||
|
||||
/* ffi_prep_args is called by the assembly routine once stack space
|
||||
has been allocated for the function's arguments */
|
||||
|
||||
void* ffi_prep_args(char *stack, extended_cif *ecif)
|
||||
{
|
||||
char *stacktemp = stack;
|
||||
int i, s;
|
||||
ffi_type **arg;
|
||||
int count = 0;
|
||||
int nfixedargs;
|
||||
|
||||
nfixedargs = ecif->cif->nfixedargs;
|
||||
arg = ecif->cif->arg_types;
|
||||
void **argv = ecif->avalue;
|
||||
|
||||
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
|
||||
{
|
||||
*(void **) stack = ecif->rvalue;
|
||||
stack += 4;
|
||||
count = 4;
|
||||
}
|
||||
for(i=0; i<ecif->cif->nargs; i++)
|
||||
{
|
||||
|
||||
/* variadic args are saved on stack */
|
||||
if ((nfixedargs == 0) && (count < 24))
|
||||
{
|
||||
count = 24;
|
||||
stack = stacktemp + 24;
|
||||
}
|
||||
nfixedargs--;
|
||||
|
||||
s = 4;
|
||||
switch((*arg)->type)
|
||||
{
|
||||
case FFI_TYPE_STRUCT:
|
||||
*(void **)stack = *argv;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT8:
|
||||
*(signed int *) stack = (signed int)*(SINT8 *)(* argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT8:
|
||||
*(unsigned int *) stack = (unsigned int)*(UINT8 *)(* argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
*(signed int *) stack = (signed int)*(SINT16 *)(* argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_UINT16:
|
||||
*(unsigned int *) stack = (unsigned int)*(UINT16 *)(* argv);
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_POINTER:
|
||||
*(int *)stack = *(int*)(*argv);
|
||||
break;
|
||||
|
||||
default: /* 8 byte types */
|
||||
if (count == 20) /* never split arguments */
|
||||
{
|
||||
stack += 4;
|
||||
count += 4;
|
||||
}
|
||||
s = (*arg)->size;
|
||||
memcpy(stack, *argv, s);
|
||||
break;
|
||||
}
|
||||
|
||||
stack += s;
|
||||
count += s;
|
||||
argv++;
|
||||
arg++;
|
||||
}
|
||||
return stacktemp + ((count>24)?24:0);
|
||||
}
|
||||
|
||||
extern void ffi_call_SYSV(unsigned,
|
||||
extended_cif *,
|
||||
void *(*)(int *, extended_cif *),
|
||||
unsigned *,
|
||||
void (*fn)(void),
|
||||
unsigned);
|
||||
|
||||
|
||||
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
|
||||
{
|
||||
int i;
|
||||
int size;
|
||||
ffi_type **arg;
|
||||
|
||||
/* Calculate size to allocate on stack */
|
||||
|
||||
for(i = 0, arg = cif->arg_types, size=0; i < cif->nargs; i++, arg++)
|
||||
{
|
||||
if ((*arg)->type == FFI_TYPE_STRUCT)
|
||||
size += 4;
|
||||
else
|
||||
if ((*arg)->size <= 4)
|
||||
size += 4;
|
||||
else
|
||||
size += 8;
|
||||
}
|
||||
|
||||
/* for variadic functions more space is needed on the stack */
|
||||
if (cif->nargs != cif->nfixedargs)
|
||||
size += 24;
|
||||
|
||||
if (cif->rtype->type == FFI_TYPE_STRUCT)
|
||||
size += 4;
|
||||
|
||||
|
||||
extended_cif ecif;
|
||||
ecif.cif = cif;
|
||||
ecif.avalue = avalue;
|
||||
ecif.rvalue = rvalue;
|
||||
|
||||
switch (cif->abi)
|
||||
{
|
||||
case FFI_SYSV:
|
||||
ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags);
|
||||
break;
|
||||
default:
|
||||
FFI_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5,
|
||||
unsigned long r6, unsigned long r7, unsigned long r8)
|
||||
{
|
||||
register int *sp __asm__ ("r17");
|
||||
register int *r13 __asm__ ("r13");
|
||||
|
||||
ffi_closure* closure = (ffi_closure*) r13;
|
||||
char *stack_args = sp;
|
||||
|
||||
/* Lay the register arguments down in a continuous chunk of memory. */
|
||||
unsigned register_args[6] =
|
||||
{ r3, r4, r5, r6, r7, r8 };
|
||||
|
||||
/* Pointer to a struct return value. */
|
||||
void *struct_rvalue = (void *) r3;
|
||||
|
||||
ffi_cif *cif = closure->cif;
|
||||
ffi_type **arg_types = cif->arg_types;
|
||||
void **avalue = alloca (cif->nargs * sizeof(void *));
|
||||
char *ptr = (char *) register_args;
|
||||
int count = 0;
|
||||
int nfixedargs = cif->nfixedargs;
|
||||
int i;
|
||||
|
||||
/* preserve struct type return pointer passing */
|
||||
|
||||
if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
|
||||
{
|
||||
ptr += 4;
|
||||
count = 4;
|
||||
}
|
||||
|
||||
/* Find the address of each argument. */
|
||||
for (i = 0; i < cif->nargs; i++)
|
||||
{
|
||||
|
||||
/* variadic args are saved on stack */
|
||||
if ((nfixedargs == 0) && (count < 24))
|
||||
{
|
||||
ptr = stack_args;
|
||||
count = 24;
|
||||
}
|
||||
nfixedargs--;
|
||||
|
||||
switch (arg_types[i]->type)
|
||||
{
|
||||
case FFI_TYPE_SINT8:
|
||||
case FFI_TYPE_UINT8:
|
||||
avalue[i] = ptr + 3;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT16:
|
||||
case FFI_TYPE_UINT16:
|
||||
avalue[i] = ptr + 2;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_SINT32:
|
||||
case FFI_TYPE_UINT32:
|
||||
case FFI_TYPE_FLOAT:
|
||||
case FFI_TYPE_POINTER:
|
||||
avalue[i] = ptr;
|
||||
break;
|
||||
|
||||
case FFI_TYPE_STRUCT:
|
||||
avalue[i] = *(void**)ptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* 8-byte values */
|
||||
|
||||
/* arguments are never splitted */
|
||||
if (ptr == ®ister_args[5])
|
||||
ptr = stack_args;
|
||||
avalue[i] = ptr;
|
||||
ptr += 4;
|
||||
count += 4;
|
||||
break;
|
||||
}
|
||||
ptr += 4;
|
||||
count += 4;
|
||||
|
||||
/* If we've handled more arguments than fit in registers,
|
||||
start looking at the those passed on the stack. */
|
||||
|
||||
if (count == 24)
|
||||
ptr = stack_args;
|
||||
}
|
||||
|
||||
if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
|
||||
{
|
||||
(closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
|
||||
} else
|
||||
{
|
||||
long long rvalue;
|
||||
(closure->fun) (cif, &rvalue, avalue, closure->user_data);
|
||||
if (cif->rtype)
|
||||
asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ffi_status
|
||||
ffi_prep_closure_loc (ffi_closure* closure,
|
||||
ffi_cif* cif,
|
||||
void (*fun)(ffi_cif*,void*,void**,void*),
|
||||
void *user_data,
|
||||
void *codeloc)
|
||||
{
|
||||
unsigned short *tramp = (unsigned short *) closure->tramp;
|
||||
unsigned long fn = (unsigned long) ffi_closure_SYSV;
|
||||
unsigned long cls = (unsigned long) codeloc;
|
||||
|
||||
if (cif->abi != FFI_SYSV)
|
||||
return FFI_BAD_ABI;
|
||||
|
||||
closure->cif = cif;
|
||||
closure->user_data = user_data;
|
||||
closure->fun = fun;
|
||||
|
||||
/* write pointers to temporary registers */
|
||||
tramp[0] = (0x6 << 10) | (13 << 5); /* l.movhi r13, ... */
|
||||
tramp[1] = cls >> 16;
|
||||
tramp[2] = (0x2a << 10) | (13 << 5) | 13; /* l.ori r13, r13, ... */
|
||||
tramp[3] = cls & 0xFFFF;
|
||||
|
||||
tramp[4] = (0x6 << 10) | (15 << 5); /* l.movhi r15, ... */
|
||||
tramp[5] = fn >> 16;
|
||||
tramp[6] = (0x2a << 10) | (15 << 5) | 15; /* l.ori r15, r15 ... */
|
||||
tramp[7] = fn & 0xFFFF;
|
||||
|
||||
tramp[8] = (0x11 << 10); /* l.jr r15 */
|
||||
tramp[9] = 15 << 11;
|
||||
|
||||
tramp[10] = (0x2a << 10) | (17 << 5) | 1; /* l.ori r17, r1, ... */
|
||||
tramp[11] = 0x0;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
|
||||
ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
|
||||
{
|
||||
cif->flags = 0;
|
||||
|
||||
/* structures are returned as pointers */
|
||||
if (cif->rtype->type == FFI_TYPE_STRUCT)
|
||||
cif->flags = FFI_TYPE_STRUCT;
|
||||
else
|
||||
if (cif->rtype->size > 4)
|
||||
cif->flags = FFI_TYPE_UINT64;
|
||||
|
||||
cif->nfixedargs = cif->nargs;
|
||||
|
||||
return FFI_OK;
|
||||
}
|
||||
|
||||
|
||||
ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
|
||||
unsigned int nfixedargs, unsigned int ntotalargs)
|
||||
{
|
||||
ffi_status status;
|
||||
|
||||
status = ffi_prep_cif_machdep (cif);
|
||||
cif->nfixedargs = nfixedargs;
|
||||
return status;
|
||||
}
|
||||
58
src/or1k/ffitarget.h
Normal file
58
src/or1k/ffitarget.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
ffitarget.h - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
|
||||
|
||||
OpenRISC Target configuration macros
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#ifndef LIBFFI_TARGET_H
|
||||
#define LIBFFI_TARGET_H
|
||||
|
||||
#ifndef LIBFFI_H
|
||||
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
|
||||
#endif
|
||||
|
||||
/* ---- System specific configurations ----------------------------------- */
|
||||
|
||||
#ifndef LIBFFI_ASM
|
||||
typedef unsigned long ffi_arg;
|
||||
typedef signed long ffi_sarg;
|
||||
|
||||
typedef enum ffi_abi {
|
||||
FFI_FIRST_ABI = 0,
|
||||
FFI_SYSV,
|
||||
FFI_LAST_ABI,
|
||||
FFI_DEFAULT_ABI = FFI_SYSV
|
||||
} ffi_abi;
|
||||
#endif
|
||||
|
||||
/* ---- Definitions for closures ----------------------------------------- */
|
||||
|
||||
#define FFI_CLOSURES 1
|
||||
#define FFI_NATIVE_RAW_API 0
|
||||
#define FFI_TRAMPOLINE_SIZE (24)
|
||||
|
||||
#define FFI_TARGET_SPECIFIC_VARIADIC 1
|
||||
#define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs;
|
||||
|
||||
#endif
|
||||
|
||||
107
src/or1k/sysv.S
Normal file
107
src/or1k/sysv.S
Normal file
@@ -0,0 +1,107 @@
|
||||
/* -----------------------------------------------------------------------
|
||||
sysv.S - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
|
||||
|
||||
OpenRISC Foreign Function Interface
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
``Software''), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
----------------------------------------------------------------------- */
|
||||
|
||||
#define LIBFFI_ASM
|
||||
#include <fficonfig.h>
|
||||
#include <ffi.h>
|
||||
|
||||
.text
|
||||
.globl ffi_call_SYSV
|
||||
.type ffi_call_SYSV, @function
|
||||
/*
|
||||
r3: size to allocate on stack
|
||||
r4: extended cif structure
|
||||
r5: function pointer ffi_prep_args
|
||||
r6: ret address
|
||||
r7: function to call
|
||||
r8: flag for return type
|
||||
*/
|
||||
|
||||
ffi_call_SYSV:
|
||||
/* Store registers used on stack */
|
||||
l.sw -4(r1), r9 /* return address */
|
||||
l.sw -8(r1), r1 /* stack address */
|
||||
l.sw -12(r1), r14 /* callee saved registers */
|
||||
l.sw -16(r1), r16
|
||||
l.sw -20(r1), r18
|
||||
l.sw -24(r1), r20
|
||||
|
||||
l.ori r14, r1, 0x0 /* save stack pointer */
|
||||
l.addi r1, r1, -24
|
||||
|
||||
l.ori r16, r7, 0x0 /* save function address */
|
||||
l.ori r18, r6, 0x0 /* save ret address */
|
||||
l.ori r20, r8, 0x0 /* save flag */
|
||||
|
||||
l.sub r1, r1, r3 /* reserve space on stack */
|
||||
|
||||
/* Call ffi_prep_args */
|
||||
l.ori r3, r1, 0x0 /* first argument stack address, second already ecif */
|
||||
l.jalr r5
|
||||
l.nop
|
||||
|
||||
/* Load register arguments and call*/
|
||||
|
||||
l.lwz r3, 0(r1)
|
||||
l.lwz r4, 4(r1)
|
||||
l.lwz r5, 8(r1)
|
||||
l.lwz r6, 12(r1)
|
||||
l.lwz r7, 16(r1)
|
||||
l.lwz r8, 20(r1)
|
||||
l.ori r1, r11, 0x0 /* new stack pointer */
|
||||
l.jalr r16
|
||||
l.nop
|
||||
|
||||
/* handle return values */
|
||||
|
||||
l.sfeqi r20, FFI_TYPE_STRUCT
|
||||
l.bf ret /* structs don't return an rvalue */
|
||||
l.nop
|
||||
|
||||
/* copy ret address */
|
||||
|
||||
l.sfeqi r20, FFI_TYPE_UINT64
|
||||
l.bnf four_byte_ret /* 8 byte value is returned */
|
||||
l.nop
|
||||
|
||||
l.sw 4(r18), r12
|
||||
|
||||
four_byte_ret:
|
||||
l.sw 0(r18), r11
|
||||
|
||||
ret:
|
||||
/* return */
|
||||
l.ori r1, r14, 0x0 /* reset stack pointer */
|
||||
l.lwz r9, -4(r1)
|
||||
l.lwz r1, -8(r1)
|
||||
l.lwz r14, -12(r1)
|
||||
l.lwz r16, -16(r1)
|
||||
l.lwz r18, -20(r1)
|
||||
l.lwz r20, -24(r1)
|
||||
l.jr r9
|
||||
l.nop
|
||||
|
||||
.size ffi_call_SYSV, .-ffi_call_SYSV
|
||||
Reference in New Issue
Block a user