diff options
author | Waldemar Brodkorb <wbx@openadk.org> | 2014-09-20 22:36:23 +0200 |
---|---|---|
committer | Waldemar Brodkorb <wbx@openadk.org> | 2014-09-22 20:35:40 +0200 |
commit | 4c3023bc803012656cf45749960282351efc8020 (patch) | |
tree | 979feef511fde3dbe564e5362e89a2e8b793909e /libc/sysdeps | |
parent | 51f9b66d2fee1c7c1088b548751ac64131220b6e (diff) |
xtensa: add support for NPTL
Changes from:
https://github.com/foss-xtensa/uClibc/commits/xtensa_nptl
Author: Chris Zankel <chris@zankel.net>
Author: Baruch Siach <baruch@tkos.co.il>
Diffstat (limited to 'libc/sysdeps')
-rw-r--r-- | libc/sysdeps/linux/xtensa/Makefile.arch | 5 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/clone.S | 101 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/fork.c | 8 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/jmpbuf-unwind.h | 38 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/sys/ptrace.h | 155 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/sysdep.h | 39 | ||||
-rw-r--r-- | libc/sysdeps/linux/xtensa/vfork.S | 104 |
7 files changed, 310 insertions, 140 deletions
diff --git a/libc/sysdeps/linux/xtensa/Makefile.arch b/libc/sysdeps/linux/xtensa/Makefile.arch index 277a1e325..b9b6b87d5 100644 --- a/libc/sysdeps/linux/xtensa/Makefile.arch +++ b/libc/sysdeps/linux/xtensa/Makefile.arch @@ -5,7 +5,10 @@ # Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. # -CSRC-y := brk.c fork.c sigaction.c __syscall_error.c +CSRC-y := brk.c sigaction.c __syscall_error.c SSRC-y := bsd-_setjmp.S bsd-setjmp.S setjmp.S clone.S \ sigrestorer.S syscall.S mmap.S windowspill.S __longjmp.S vfork.S + +CSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += fork.c +SSRC-$(if $(UCLIBC_HAS_THREADS_NATIVE),,y) += clone.S diff --git a/libc/sysdeps/linux/xtensa/clone.S b/libc/sysdeps/linux/xtensa/clone.S index aa79aa736..34d68a875 100644 --- a/libc/sysdeps/linux/xtensa/clone.S +++ b/libc/sysdeps/linux/xtensa/clone.S @@ -1,34 +1,38 @@ -/* Copyright (C) 2001, 2005, 2007 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2005 Free Software Foundation, Inc. The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. + Library General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <http://www.gnu.org/licenses/>. */ + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ /* clone is even more special than fork as it mucks with stacks - and invokes a function in the right context after it's all over. */ + and invokes a function in the right context after its all over. */ -#include "sysdep.h" -#include <sys/syscall.h> +#include <features.h> +#include <sysdep.h> #define _ERRNO_H 1 #include <bits/errno.h> +#ifdef RESET_PID +#include <tls.h> +#endif +#define __ASSEMBLY__ +#include <linux/sched.h> -/* int clone (a2 = int (*fn)(void *arg), - a3 = void *child_stack, - a4 = int flags, - a5 = void *arg, - a6 = pid_t *ptid, - a7 = struct user_desc *tls, - 16(sp) = pid_t *ctid) */ +/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg, + a2 a3 a4 a5 + pid_t *ptid, struct user_desc *tls, pid_t *ctid) + a6 a7 16(sp) +*/ .text ENTRY (__clone) @@ -39,7 +43,7 @@ ENTRY (__clone) /* a2 and a3 are candidates for destruction by system-call return parameters. We don't need the stack pointer after the system - call. We trust that the kernel will preserve a7, a9, and a6. */ + call. We trust that the kernel will preserve a6, a7 and a9. */ mov a9, a5 /* save function argument */ mov a5, a7 @@ -48,19 +52,18 @@ ENTRY (__clone) mov a6, a4 mov a4, a8 l32i a8, a1, 16 /* child_tid */ - movi a2, SYS_ify (clone) - - /* syscall (a2 = NR_clone, - a6 = clone_flags, - a3 = usp, - a4 = parent_tid, - a5 = child_tls, - a8 = child_tid) */ + movi a2, SYS_ify(clone) + + /* syscall(NR_clone,clone_flags, usp, parent_tid, child_tls, child_tid) + a2 a6 a3 a4 a5 a8 + */ + syscall bltz a2, SYSCALL_ERROR_LABEL beqz a2, .Lthread_start - /* Fall through for parent. */ + /* fall through for parent */ + .Lpseudo_end: retw @@ -69,32 +72,38 @@ ENTRY (__clone) j SYSCALL_ERROR_LABEL .Lthread_start: - /* Start child thread. */ - movi a0, 0 /* terminate the stack frame */ + +#if CLONE_THREAD != 0x00010000 || CLONE_VM != 0x00000100 +# error invalid values for CLONE_THREAD or CLONE_VM +#endif #ifdef RESET_PID - /* Check and see if we need to reset the PID. */ - bbsi.l a6, 16, 1f /* CLONE_THREAD = 0x00010000 */ + bbsi.l a6, 16, .Lskip_restore_pid /* CLONE_THREAD = 0x00010000 */ movi a2, -1 - bbsi.l a6, 8, 2f /* CLONE_VM = 0x00000100 */ - movi a2, SYS_ify (getpid) + bbsi a6, 8, .Lgotpid /* CLONE_VM = 0x00000100 */ + movi a2, SYS_ify(getpid) syscall -2: rur a3, THREADPTR - movi a4, PID_OFFSET - add a4, a4, a3 - s32i a2, a4, 0 - movi a4, TID_OFFSET - add a4, a4, a3 - s32i a2, a3, 0 -1: -#endif /* RESET_PID */ - +.Lgotpid: + rur a3, threadptr + movi a0, TLS_PRE_TCB_SIZE + sub a3, a3, a0 + s32i a2, a3, PID + s32i a2, a3, TID +.Lskip_restore_pid: +#endif + + /* start child thread */ + movi a0, 0 /* terminate the stack frame */ mov a6, a9 /* load up the 'arg' parameter */ callx4 a7 /* call the user's function */ /* Call _exit. Note that any return parameter from the user's - function in a6 is seen as inputs to _exit. */ - movi a2, JUMPTARGET(_exit) + function in a6 is seen as inputs to _exit. */ +#ifdef PIC + movi a2, _exit@PLT +#else + movi a2, _exit +#endif callx4 a2 PSEUDO_END (__clone) diff --git a/libc/sysdeps/linux/xtensa/fork.c b/libc/sysdeps/linux/xtensa/fork.c index e9b681c67..4e4f937a0 100644 --- a/libc/sysdeps/linux/xtensa/fork.c +++ b/libc/sysdeps/linux/xtensa/fork.c @@ -20,6 +20,10 @@ pid_t fork(void) { return (pid_t) INLINE_SYSCALL(clone, 2, SIGCHLD, 0); } -lt_strong_alias(fork) -lt_libc_hidden(fork) +# ifdef __UCLIBC_HAS_THREADS__ +strong_alias(fork,__libc_fork) +libc_hidden_weak(fork) +# else +libc_hidden_def(fork) +# endif #endif diff --git a/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h b/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h index 41f81dbad..4516d9398 100644 --- a/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h +++ b/libc/sysdeps/linux/xtensa/jmpbuf-unwind.h @@ -1,25 +1,23 @@ -/* Copyright (C) 1997, 1998, 2007 Free Software Foundation, Inc. - This file is part of the GNU C Library. - - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - <http://www.gnu.org/licenses/>. */ - -/* Test if longjmp to JMPBUF would unwind the frame containing a local - variable at ADDRESS. */ - +/* + * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org> + * + * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball. + */ #include <setjmp.h> #include <jmpbuf-offsets.h> +/* Test if longjmp to JMPBUF would unwind the frame + containing a local variable at ADDRESS. */ #define _JMPBUF_UNWINDS(jmpbuf, address) \ ((void *) (address) < (void *) (jmpbuf)[JB_SP]) + +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <stdint.h> +#include <unwind.h> + +#define _JMPBUF_CFA_UNWINDS_ADJ(_jmpbuf, _context, _adj) \ + _JMPBUF_UNWINDS_ADJ (_jmpbuf, (void *) _Unwind_GetCFA (_context), _adj) + +#define _JMPBUF_UNWINDS_ADJ(_jmpbuf, _address, _adj) \ + ((uintptr_t) (_address) - (_adj) < (uintptr_t) (_jmpbuf)[JB_SP] - (_adj)) +#endif diff --git a/libc/sysdeps/linux/xtensa/sys/ptrace.h b/libc/sysdeps/linux/xtensa/sys/ptrace.h new file mode 100644 index 000000000..882b8c8ed --- /dev/null +++ b/libc/sysdeps/linux/xtensa/sys/ptrace.h @@ -0,0 +1,155 @@ +/* `ptrace' debugger support interface. Linux version. + Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 + Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SYS_PTRACE_H +#define _SYS_PTRACE_H 1 + +#include <features.h> + +/* Kludge away careless namespace pollution from the kernel. */ + +#undef PTRACE_GETREGS +#undef PTRACE_SETREGS +#undef PTRACE_GETFPREGS +#undef PTRACE_SETFPREGS +#undef PTRACE_GETFPREGSIZE + + +__BEGIN_DECLS + +/* Type of the REQUEST argument to `ptrace.' */ +enum __ptrace_request +{ + /* Indicate that the process making this request should be traced. + All signals received by this process can be intercepted by its + parent, and its parent can use the other `ptrace' requests. */ + PTRACE_TRACEME = 0, +#define PT_TRACE_ME PTRACE_TRACEME + + /* Return the word in the process's text space at address ADDR. */ + PTRACE_PEEKTEXT = 1, +#define PT_READ_I PTRACE_PEEKTEXT + + /* Return the word in the process's data space at address ADDR. */ + PTRACE_PEEKDATA = 2, +#define PT_READ_D PTRACE_PEEKDATA + + /* Return the word in the process's user area at offset ADDR. */ + PTRACE_PEEKUSER = 3, +#define PT_READ_U PTRACE_PEEKUSER + + /* Write the word DATA into the process's text space at address ADDR. */ + PTRACE_POKETEXT = 4, +#define PT_WRITE_I PTRACE_POKETEXT + + /* Write the word DATA into the process's data space at address ADDR. */ + PTRACE_POKEDATA = 5, +#define PT_WRITE_D PTRACE_POKEDATA + + /* Write the word DATA into the process's user area at offset ADDR. */ + PTRACE_POKEUSER = 6, +#define PT_WRITE_U PTRACE_POKEUSER + + /* Continue the process. */ + PTRACE_CONT = 7, +#define PT_CONTINUE PTRACE_CONT + + /* Kill the process. */ + PTRACE_KILL = 8, +#define PT_KILL PTRACE_KILL + + /* Single step the process. + This is not supported on all machines. */ + PTRACE_SINGLESTEP = 9, +#define PT_STEP PTRACE_SINGLESTEP + + /* Get all general purpose registers used by a processes. + This is not supported on all machines. */ + PTRACE_GETREGS = 12, +#define PT_GETREGS PTRACE_GETREGS + + /* Set all general purpose registers used by a processes. + This is not supported on all machines. */ + PTRACE_SETREGS = 13, +#define PT_SETREGS PTRACE_SETREGS + + /* Get all floating point registers used by a processes. + This is not supported on all machines. */ + PTRACE_GETFPREGS = 14, +#define PT_GETFPREGS PTRACE_GETFPREGS + + /* Set all floating point registers used by a processes. + This is not supported on all machines. */ + PTRACE_SETFPREGS = 15, +#define PT_SETFPREGS PTRACE_SETFPREGS + + /* Attach to a process that is already running. */ + PTRACE_ATTACH = 16, +#define PT_ATTACH PTRACE_ATTACH + + /* Detach from a process attached to with PTRACE_ATTACH. */ + PTRACE_DETACH = 17, +#define PT_DETACH PTRACE_DETACH + + /* Get size required for the buffer holding the floating point registers. + This is not supported on all machines. */ + PTRACE_GETFPREGSIZE = 18, +#define PT_GETFPREGSIZE PTRACE_GETFPREGSIZE + + /* Continue and stop at the next (return from) syscall. */ + PTRACE_SYSCALL = 24 +#define PT_SYSCALL PTRACE_SYSCALL +}; + +/* Options set using PTRACE_SETOPTIONS. */ +enum __ptrace_setoptions { + PTRACE_O_TRACESYSGOOD = 0x00000001, + PTRACE_O_TRACEFORK = 0x00000002, + PTRACE_O_TRACEVFORK = 0x00000004, + PTRACE_O_TRACECLONE = 0x00000008, + PTRACE_O_TRACEEXEC = 0x00000010, + PTRACE_O_TRACEVFORKDONE = 0x00000020, + PTRACE_O_TRACEEXIT = 0x00000040, + PTRACE_O_MASK = 0x0000007f +}; + +/* Wait extended result codes for the above trace options. */ +enum __ptrace_eventcodes { + PTRACE_EVENT_FORK = 1, + PTRACE_EVENT_VFORK = 2, + PTRACE_EVENT_CLONE = 3, + PTRACE_EVENT_EXEC = 4, + PTRACE_EVENT_VFORK_DONE = 5, + PTRACE_EVENT_EXIT = 6 +}; + +/* Perform process tracing functions. REQUEST is one of the values + above, and determines the action to be taken. + For all requests except PTRACE_TRACEME, PID specifies the process to be + traced. + + PID and the other arguments described above for the various requests should + appear (those that are used for the particular request) as: + pid_t PID, void *ADDR, int DATA, void *ADDR2 + after REQUEST. */ +extern long int ptrace (enum __ptrace_request __request, ...) __THROW; + +__END_DECLS + +#endif /* _SYS_PTRACE_H */ diff --git a/libc/sysdeps/linux/xtensa/sysdep.h b/libc/sysdeps/linux/xtensa/sysdep.h index afe95cc6a..cab4a2f8d 100644 --- a/libc/sysdeps/linux/xtensa/sysdep.h +++ b/libc/sysdeps/linux/xtensa/sysdep.h @@ -16,6 +16,10 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#ifndef _LINUX_XTENSA_SYSDEP_H +#define _LINUX_XTENSA_SYSDEP_H 1 + +#include <common/sysdep.h> #include <sys/syscall.h> #ifdef __ASSEMBLER__ @@ -24,12 +28,6 @@ #define ASM_TYPE_DIRECTIVE(name, typearg) .type name, typearg #define ASM_SIZE_DIRECTIVE(name) .size name, . - name -#ifdef __STDC__ -#define C_LABEL(name) name : -#else -#define C_LABEL(name) name/**/: -#endif - #define ENTRY(name) \ ASM_GLOBAL_DIRECTIVE C_SYMBOL_NAME(name); \ ASM_TYPE_DIRECTIVE (C_SYMBOL_NAME(name), @function); \ @@ -52,6 +50,15 @@ #undef END #define END(name) ASM_SIZE_DIRECTIVE(name) +/* Local label name for asm code. */ +#ifndef L +# ifdef HAVE_ELF +# define L(name) .L##name +# else +# define L(name) name +# endif +#endif + /* Define a macro for this directive so it can be removed in a few places. */ #define LITERAL_POSITION .literal_position @@ -123,19 +130,7 @@ #define PSEUDO_END_ERRVAL(name) \ END (name) -#undef ret_ERRVAL -#define ret_ERRVAL retw - -#if defined RTLD_PRIVATE_ERRNO -# define SYSCALL_ERROR_HANDLER \ -0: movi a4, rtld_errno; \ - neg a2, a2; \ - s32i a2, a4, 0; \ - movi a2, -1; \ - j .Lpseudo_end; - -#elif defined _LIBC_REENTRANT - +#if defined _LIBC_REENTRANT # if defined USE___THREAD # ifndef NOT_IN_libc # define SYSCALL_ERROR_ERRNO __libc_errno @@ -170,3 +165,9 @@ #endif /* _LIBC_REENTRANT */ #endif /* __ASSEMBLER__ */ + +/* Pointer mangling is not yet supported for Xtensa. */ +#define PTR_MANGLE(var) (void) (var) +#define PTR_DEMANGLE(var) (void) (var) + +#endif /* _LINUX_XTENSA_SYSDEP_H */ diff --git a/libc/sysdeps/linux/xtensa/vfork.S b/libc/sysdeps/linux/xtensa/vfork.S index f094ae38f..6aced0a50 100644 --- a/libc/sysdeps/linux/xtensa/vfork.S +++ b/libc/sysdeps/linux/xtensa/vfork.S @@ -1,4 +1,4 @@ -/* Copyright (C) 2005, 2007 Free Software Foundation, Inc. +/* Copyright (C) 2005-2013 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -19,72 +19,67 @@ #include <sys/syscall.h> #define _SIGNAL_H #include <bits/signum.h> +#define __ASSEMBLY__ +#include <linux/sched.h> -/* Clone the calling process, but without copying the whole address space. +/* + Clone the calling process, but without copying the whole address space. The calling process is suspended until the new process exits or is replaced by a call to `execve'. Return -1 for errors, 0 to the new process, and the process ID of the new process to the old process. Note that it is important that we don't create a new stack frame for the - caller. */ + caller. - -/* The following are defined in linux/sched.h, which unfortunately - is not safe for inclusion in an assembly file. */ -#define CLONE_VM 0x00000100 /* set if VM shared between processes */ -#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to - wake it up on mm_release */ +*/ #ifndef SAVE_PID -#define SAVE_PID +#define SAVE_PID(a,b,c,d) #endif - #ifndef RESTORE_PID -#define RESTORE_PID +#define RESTORE_PID(a,b,c) +#endif +#ifndef RESTORE_PID12 +#define RESTORE_PID12(a,b,c) #endif +/* + pid_t vfork(void); + Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) + */ -/* pid_t vfork(void); - Implemented as __clone_syscall(CLONE_VFORK | CLONE_VM | SIGCHLD, 0) */ HIDDEN_ENTRY (__vfork) + .literal .Ljumptable, 0, .L4, .L8, .L12 - movi a6, .Ljumptable - extui a2, a0, 30, 2 /* call-size: call4/8/12 = 1/2/3 */ - addx4 a4, a2, a6 /* find return address in jumptable */ - l32i a4, a4, 0 - add a4, a4, a6 - + mov a3, a0 # move return address out of the way + movi a0, .Ljumptable + extui a2, a3, 30, 2 # call-size: call4/8/12 = 1/2/3 + addx4 a0, a2, a0 # find return address in jumptable slli a2, a2, 30 - xor a3, a0, a2 /* remove call-size from return addr */ - extui a5, a4, 30, 2 /* get high bits of jump target */ - slli a5, a5, 30 - or a3, a3, a5 /* stuff them into the return address */ - xor a4, a4, a5 /* clear high bits of jump target */ - or a0, a4, a2 /* create temporary return address */ - retw /* "return" to .L4, .L8, or .L12 */ - - .align 4 -.Ljumptable: - .word 0 - .word .L4 - .Ljumptable - .word .L8 - .Ljumptable - .word .L12 - .Ljumptable + l32i a0, a0, 0 + + xor a3, a3, a2 # remove call-size from return address + or a0, a0, a2 # create temporary return address + retw /* a7: return address */ + .L4: mov a12, a2 mov a13, a3 - SAVE_PID + SAVE_PID(a5,a15,a2,a3) + + /* use syscall 'clone' and set new stack pointer to the same address */ - /* Use syscall 'clone'. Set new stack pointer to the same address. */ - movi a2, SYS_ify (clone) + movi a2, SYS_ify(clone) movi a3, 0 movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD + syscall - RESTORE_PID + RESTORE_PID(a5,a15,a2) movi a5, -4096 @@ -94,22 +89,24 @@ HIDDEN_ENTRY (__vfork) bgeu a6, a5, 1f jx a7 -1: call4 .Lerr /* returns to original caller */ +1: call4 .Lerr /* a11: return address */ + .L8: mov a12, a2 mov a13, a3 mov a14, a6 - SAVE_PID + SAVE_PID(a9,a15,a2,a3) - movi a2, SYS_ify (clone) + movi a2, SYS_ify(clone) movi a3, 0 movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD + syscall - RESTORE_PID + RESTORE_PID(a9,a15,a2) movi a9, -4096 @@ -120,22 +117,25 @@ HIDDEN_ENTRY (__vfork) bgeu a10, a9, 1f jx a11 -1: call8 .Lerr /* returns to original caller */ + +1: call8 .Lerr /* a15: return address */ + .L12: mov a12, a2 mov a13, a3 mov a14, a6 - SAVE_PID + SAVE_PID (a2,a3,a2,a6) - movi a2, SYS_ify (clone) + movi a2, SYS_ify(clone) movi a3, 0 movi a6, CLONE_VM | CLONE_VFORK | SIGCHLD + syscall - RESTORE_PID + RESTORE_PID12(a3,a6,a15) mov a3, a13 movi a13, -4096 @@ -147,18 +147,18 @@ HIDDEN_ENTRY (__vfork) bgeu a14, a13, 1f jx a15 -1: call12 .Lerr /* returns to original caller */ +1: call12 .Lerr .align 4 + .Lerr: entry a1, 16 - /* Restore the return address. */ - extui a4, a0, 30, 2 /* get the call-size bits */ + /* Restore return address */ + + extui a4, a0, 30, 2 slli a4, a4, 30 - slli a3, a3, 2 /* clear high bits of target address */ - srli a3, a3, 2 - or a0, a3, a4 /* combine them */ + or a0, a3, a4 PSEUDO_END (__vfork) .Lpseudo_end: |