Openwall GNU/*/Linux - a small security-enhanced Linux distro for servers
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 27 Sep 2018 22:46:33 -0400
From: Rich Felker <dalias@...c.org>
To: musl@...ts.openwall.com
Subject: Re: riscv port for review

On Thu, Sep 27, 2018 at 10:24:04PM -0400, Rich Felker wrote:
> Pulled from here:
> https://github.com/riscv/riscv-musl/commit/6a4f4a9c774608add4b02f95322518bd2f5f51ee
> 
> Attached for review.

Review inline below:

> diff --git a/arch/riscv32/atomic_arch.h b/arch/riscv32/atomic_arch.h
> new file mode 100644
> index 0000000..93c89cc
> --- /dev/null
> +++ b/arch/riscv32/atomic_arch.h
> @@ -0,0 +1,35 @@
> +#define a_barrier a_barrier
> +static inline void a_barrier()
> +{
> +	__asm__ __volatile__ ("fence rw,rw" : : : "memory");
> +}
> +
> +#define a_ll a_ll
> +static inline int a_ll(volatile int *p)
> +{
> +	int v;
> +	__asm__ __volatile__ ("lr.w %0, (%1)" : "=&r"(v) : "r"(p));
> +	return v;
> +}
> +
> +#define a_sc a_sc
> +static inline int a_sc(volatile int *p, int v)
> +{
> +	int r;
> +	__asm__ __volatile__ ("sc.w %0, %2, (%1)" : "=&r"(r) : "r"(p), "r"(v) : "memory");
> +	return !r;
> +}
> +
> +#define a_cas a_cas
> +static inline int a_cas(volatile int *p, int t, int s)
> +{
> +	int old, tmp;
> +	__asm__("1:  lr.w    %0, %2      \n"
> +		"    bne     %0, %3, 1f  \n"
> +		"    sc.w    %1, %4, %2  \n"
> +		"    bnez    %1, 1b      \n"
> +		"1:                      \n"
> +		: "=&r"(old), "+r"(tmp), "+A"(*p)
> +		: "r"(t), "r"(s));
> +	return old;
> +}

Why are both a_ll/a_sc and a_cas defined, and why is a_cas missing
barriers? Normally if a_ll/a_sc/a_barrier are defined, the top-level
atomic.h should be allowed to generate a_cas in terms of them.

> diff --git a/arch/riscv32/bits/signal.h b/arch/riscv32/bits/signal.h
> new file mode 100644
> index 0000000..8b992cc
> --- /dev/null
> +++ b/arch/riscv32/bits/signal.h
> @@ -0,0 +1,113 @@
> +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
> + || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
> +
> +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
> +# define MINSIGSTKSZ 2048
> +# define SIGSTKSZ 8192
> +#endif
> +
> +/* gregs[0] holds the program counter. */
> +
> +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
> +typedef unsigned long greg_t;
> +typedef unsigned long gregset_t[32];
> +
> +struct __riscv_f_ext_state {
> +	unsigned int f[32];
> +	unsigned int fcsr;
> +};
> +
> +struct __riscv_d_ext_state {
> +	unsigned long long f[32];
> +	unsigned int fcsr;
> +};
> +
> +struct __riscv_q_ext_state {
> +	unsigned long long f[64] __attribute__((aligned(16)));
> +	unsigned int fcsr;
> +	unsigned int reserved[3];
> +};
> +
> +union __riscv_fp_state {
> +	struct __riscv_f_ext_state f;
> +	struct __riscv_d_ext_state d;
> +	struct __riscv_q_ext_state q;
> +};
> +
> +typedef union __riscv_fp_state fpregset_t;
> +
> +typedef struct sigcontext {
> +	gregset_t gregs;
> +	fpregset_t fpregs;
> +} mcontext_t;
> +
> +#else
> +typedef struct {
> +	unsigned long gregs[32];
> +	unsigned long long fpregs[66];
> +} mcontext_t;
> +#endif

In the namespace-safe version of mcontext_t, the names gregs and
fpregs are not valid here. They would need to be __-prefixed or in
some other reserved namespace.

> +struct sigaltstack {
> +	void *ss_sp;
> +	int ss_flags;
> +	size_t ss_size;
> +};
> +
> +typedef struct __ucontext
> +{
> +	unsigned long uc_flags;
> +	struct __ucontext *uc_link;
> +	stack_t uc_stack;
> +	sigset_t uc_sigmask;
> +	char __unused[1024 / 8 - sizeof(sigset_t)];

This is an invalid array of size zero and should just be removed.

> +	mcontext_t uc_mcontext;
> +} ucontext_t;

...

> diff --git a/arch/riscv32/crt_arch.h b/arch/riscv32/crt_arch.h
> new file mode 100644
> index 0000000..65187e1
> --- /dev/null
> +++ b/arch/riscv32/crt_arch.h
> @@ -0,0 +1,18 @@
> +__asm__(
> +".text\n"
> +".global " START "\n"
> +".type " START ",%function\n"
> +START ":\n"
> +".weak __global_pointer$\n"
> +".hidden __global_pointer$\n\t"
> +".option push\n"
> +".option norelax\n\t"
> +"lla gp, __global_pointer$\n"
> +".option pop\n\t"
> +"mv a0, sp\n"
> +".weak _DYNAMIC\n"
> +".hidden _DYNAMIC\n\t"
> +"lla a1, _DYNAMIC\n\t"
> +"andi sp, sp, -16\n\t"
> +"jal " START "_c"
> +);
> diff --git a/arch/riscv32/pthread_arch.h b/arch/riscv32/pthread_arch.h
> new file mode 100644
> index 0000000..feffaa4
> --- /dev/null
> +++ b/arch/riscv32/pthread_arch.h
> @@ -0,0 +1,12 @@
> +static inline struct pthread *__pthread_self()
> +{
> +	char *tp;
> +	__asm__ __volatile__("mv %0, tp" : "=r"(tp));
> +	return (void *)(tp - sizeof(struct pthread));
> +}
> +
> +#define TLS_ABOVE_TP
> +#define GAP_ABOVE_TP 0
> +#define TP_ADJ(p) ((char *)p + sizeof(struct pthread))
> +
> +#define MC_PC gregs[0]
> diff --git a/arch/riscv32/reloc.h b/arch/riscv32/reloc.h
> new file mode 100644
> index 0000000..d057bbe
> --- /dev/null
> +++ b/arch/riscv32/reloc.h
> @@ -0,0 +1,27 @@
> +#if defined __riscv_float_abi_soft
> +#define RISCV_FP_SUFFIX "-sf"
> +#elif defined __riscv_float_abi_single
> +#define RISCV_FP_SUFFIX "-sp"
> +#elif defined __riscv_float_abi_double
> +#define RISCV_FP_SUFFIX ""
> +#endif
> +
> +#define RISCV_LDSO_HELPER(x) "riscv" #x
> +#define RISCV_LDSO(x) RISCV_LDSO_HELPER(x)
> +
> +#define LDSO_ARCH RISCV_LDSO(__riscv_xlen) RISCV_FP_SUFFIX

Elsewhere it looks like little/big endian are both options, but I see
no endian variant here. If so this needs to be fixed.

Also what is __riscv_xlen? A predefined macro that expands to 32 or
64? Since this file is just for 32-bit it should just be hard-coded
rather than assuming a macro would expand to the token 32 and not
(31+1) or some other expression equal to 32, I think.

> diff --git a/arch/riscv32/syscall_arch.h b/arch/riscv32/syscall_arch.h
> new file mode 100644
> index 0000000..bc60d1f
> --- /dev/null
> +++ b/arch/riscv32/syscall_arch.h
> @@ -0,0 +1,78 @@
> +#define __SYSCALL_LL_E(x) \
> +((union { long long ll; long l[2]; }){ .ll = x }).l[0], \
> +((union { long long ll; long l[2]; }){ .ll = x }).l[1]
> +#define __SYSCALL_LL_O(x) 0, __SYSCALL_LL_E((x))
> +
> +#define __asm_syscall(...) \
> +	__asm__ __volatile__ ("scall\n\t" \
> +	: "+r"(a0) : __VA_ARGS__ : "memory"); \
> +	return a0; \
> +
> +static inline long __syscall0(long n)
> +{
> +	register long a7 __asm__("a7") = n;
> +	register long a0 __asm__("a0");
> +	__asm_syscall("r"(a7))
> +}
> +
> +static inline long __syscall1(long n, long a)
> +{
> +	register long a7 __asm__("a7") = n;
> +	register long a0 __asm__("a0") = a;
> +	__asm_syscall("r"(a7), "0"(a0))
> +}
> +
> +static inline long __syscall2(long n, long a, long b)
> +{
> +	register long a7 __asm__("a7") = n;
> +	register long a0 __asm__("a0") = a;
> +	register long a1 __asm__("a1") = b;
> +	__asm_syscall("r"(a7), "0"(a0), "r"(a1))
> +}
> +
> +static inline long __syscall3(long n, long a, long b, long c)
> +{
> +	register long a7 __asm__("a7") = n;
> +	register long a0 __asm__("a0") = a;
> +	register long a1 __asm__("a1") = b;
> +	register long a2 __asm__("a2") = c;
> +	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2))
> +}
> +
> +static inline long __syscall4(long n, long a, long b, long c, long d)
> +{
> +	register long a7 __asm__("a7") = n;
> +	register long a0 __asm__("a0") = a;
> +	register long a1 __asm__("a1") = b;
> +	register long a2 __asm__("a2") = c;
> +	register long a3 __asm__("a3") = d;
> +	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2), "r"(a3))
> +}
> +
> +static inline long __syscall5(long n, long a, long b, long c, long d, long e)
> +{
> +	register long a7 __asm__("a7") = n;
> +	register long a0 __asm__("a0") = a;
> +	register long a1 __asm__("a1") = b;
> +	register long a2 __asm__("a2") = c;
> +	register long a3 __asm__("a3") = d;
> +	register long a4 __asm__("a4") = e;
> +	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4))
> +}
> +
> +static inline long __syscall6(long n, long a, long b, long c, long d, long e, long f)
> +{
> +	register long a7 __asm__("a7") = n;
> +	register long a0 __asm__("a0") = a;
> +	register long a1 __asm__("a1") = b;
> +	register long a2 __asm__("a2") = c;
> +	register long a3 __asm__("a3") = d;
> +	register long a4 __asm__("a4") = e;
> +	register long a5 __asm__("a5") = f;
> +	__asm_syscall("r"(a7), "0"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5))
> +}
> +
> +#define VDSO_USEFUL
> +/* We don't have a clock_gettime function.
> +#define VDSO_CGT_SYM "__vdso_clock_gettime"
> +#define VDSO_CGT_VER "LINUX_2.6" */

In that case VDSO_USEFUL might as well also be omitted for now.

> diff --git a/arch/riscv64/atomic_arch.h b/arch/riscv64/atomic_arch.h
> new file mode 100644
> index 0000000..018c7fd
> --- /dev/null
> +++ b/arch/riscv64/atomic_arch.h
> @@ -0,0 +1,66 @@
> +#define a_barrier a_barrier
> +static inline void a_barrier()
> +{
> +	__asm__ __volatile__ ("fence rw,rw" : : : "memory");
> +}
> +
> +#define a_ll a_ll
> +static inline int a_ll(volatile int *p)
> +{
> +	int v;
> +	__asm__ __volatile__ ("lr.w %0, %1" : "=&r"(v), "+A"(*p));
> +	return v;
> +}
> +
> +#define a_sc a_sc
> +static inline int a_sc(volatile int *p, int v)
> +{
> +	int r;
> +	__asm__ __volatile__ ("sc.w %0, %2, %1" : "=&r"(r), "+A"(*p) : "r"(v) : "memory");
> +return !r;
> +}
> +
> +#define a_cas a_cas
> +static inline int a_cas(volatile int *p, int t, int s)
> +{
> +	int old, tmp;
> +	__asm__("1:  lr.w    %0, %2      \n"
> +		"    bne     %0, %3, 1f  \n"
> +		"    sc.w    %1, %4, %2  \n"
> +		"    bnez    %1, 1b      \n"
> +		"1:                      \n"
> +		: "=&r"(old), "+r"(tmp), "+A"(*p)
> +		: "r"(t), "r"(s));
> +	return old;
> +}
> +
> +#define a_ll_p a_ll_p
> +static inline void *a_ll_p(volatile void *p)
> +{
> +	void *v;
> +	__asm__ __volatile__ ("lr.d %0, %1" : "=&r"(v), "+A"(*(long *)p));
> +	return v;
> +}
> +
> +#define a_sc_p a_sc_p
> +static inline int a_sc_p(volatile int *p, void *v)
> +{
> +	int r;
> +	__asm__ __volatile__ ("sc.d %0, %2, %1" : "=&r"(r), "+A"(*(long *)p) : "r"(v) : "memory");
> +	return !r;
> +}
> +
> +#define a_cas_p a_cas_p
> +static inline void *a_cas_p(volatile void *p, void *t, void *s)
> +{
> +	void *old;
> +	int tmp;
> +	__asm__("1:  lr.d    %0, %2      \n"
> +		"    bne     %0, %3, 1f  \n"
> +		"    sc.d    %1, %4, %2  \n"
> +		"    bnez    %1, 1b      \n"
> +		"1:                      \n"
> +		: "=&r"(old), "+r"(tmp), "+A"(*(long *)p)
> +		: "r"(t), "r"(s));
> +	return old;
> +}

Same comments about cas vs ll/sc, and lack of barrier, as 32-bit version.

> diff --git a/arch/riscv64/bits/signal.h b/arch/riscv64/bits/signal.h
> new file mode 100644
> index 0000000..8b992cc
> --- /dev/null
> +++ b/arch/riscv64/bits/signal.h
> @@ -0,0 +1,113 @@
> +#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
> + || defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
> +
> +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
> +# define MINSIGSTKSZ 2048
> +# define SIGSTKSZ 8192
> +#endif
> +
> +/* gregs[0] holds the program counter. */
> +
> +#if defined(_GNU_SOURCE) || defined(_BSD_SOURCE)
> +typedef unsigned long greg_t;
> +typedef unsigned long gregset_t[32];
> +
> +struct __riscv_f_ext_state {
> +	unsigned int f[32];
> +	unsigned int fcsr;
> +};
> +
> +struct __riscv_d_ext_state {
> +	unsigned long long f[32];
> +	unsigned int fcsr;
> +};
> +
> +struct __riscv_q_ext_state {
> +	unsigned long long f[64] __attribute__((aligned(16)));
> +	unsigned int fcsr;
> +	unsigned int reserved[3];
> +};
> +
> +union __riscv_fp_state {
> +	struct __riscv_f_ext_state f;
> +	struct __riscv_d_ext_state d;
> +	struct __riscv_q_ext_state q;
> +};
> +
> +typedef union __riscv_fp_state fpregset_t;
> +
> +typedef struct sigcontext {
> +	gregset_t gregs;
> +	fpregset_t fpregs;
> +} mcontext_t;
> +
> +#else
> +typedef struct {
> +	unsigned long gregs[32];
> +	unsigned long long fpregs[66];
> +} mcontext_t;
> +#endif
> +
> +struct sigaltstack {
> +	void *ss_sp;
> +	int ss_flags;
> +	size_t ss_size;
> +};
> +
> +typedef struct __ucontext
> +{
> +	unsigned long uc_flags;
> +	struct __ucontext *uc_link;
> +	stack_t uc_stack;
> +	sigset_t uc_sigmask;
> +	char __unused[1024 / 8 - sizeof(sigset_t)];
> +	mcontext_t uc_mcontext;
> +} ucontext_t;

Same issues here as 32-bit.

> diff --git a/arch/riscv64/reloc.h b/arch/riscv64/reloc.h
> new file mode 100644
> index 0000000..8bd90dd
> --- /dev/null
> +++ b/arch/riscv64/reloc.h
> @@ -0,0 +1,27 @@
> +#if defined __riscv_float_abi_soft
> +#define RISCV_FP_SUFFIX "-sf"
> +#elif defined __riscv_float_abi_single
> +#define RISCV_FP_SUFFIX "-sp"
> +#elif defined __riscv_float_abi_double
> +#define RISCV_FP_SUFFIX ""
> +#endif
> +
> +#define RISCV_LDSO_HELPER(x) "riscv" #x
> +#define RISCV_LDSO(x) RISCV_LDSO_HELPER(x)
> +
> +#define LDSO_ARCH RISCV_LDSO(__riscv_xlen) RISCV_FP_SUFFIX

Same here.

> diff --git a/configure b/configure
> index 997e665..4d3d8b4 100755
> --- a/configure
> +++ b/configure
> @@ -322,6 +322,8 @@ microblaze*) ARCH=microblaze ;;
>  or1k*) ARCH=or1k ;;
>  powerpc64*) ARCH=powerpc64 ;;
>  powerpc*) ARCH=powerpc ;;
> +riscv64*) ARCH=riscv64 ;;
> +riscv*) ARCH=riscv32 ;;
>  sh[1-9bel-]*|sh|superh*) ARCH=sh ;;
>  s390x*) ARCH=s390x ;;
>  unknown) fail "$0: unable to detect target arch; try $0 --target=..." ;;
> @@ -640,6 +642,11 @@ trycppif __LITTLE_ENDIAN__ "$t" && SUBARCH=${SUBARCH}le
>  trycppif _SOFT_FLOAT "$t" && fail "$0: error: soft-float not supported on powerpc64"
>  fi
>  
> +if test "$ARCH" = "riscv" || test "$ARCH" = "riscv64" ; then
> +trycppif "RISCVEB || _RISCVEB || __RISCVEB || __RISCVEB__" "$t" && SUBARCH=${SUBARCH}eb

Predefined macros that violate the namespace (RISCVEB) shouldn't be
defined or observed.

> +trycppif __riscv_soft_float "$t" && SUBARCH=${SUBARCH}-sf
> +fi
> +
>  if test "$ARCH" = "sh" ; then
>  tryflag CFLAGS_AUTO -Wa,--isa=any
>  trycppif __BIG_ENDIAN__ "$t" && SUBARCH=${SUBARCH}eb
> diff --git a/crt/riscv32/crti.s b/crt/riscv32/crti.s
> new file mode 100644
> index 0000000..6916bfd
> --- /dev/null
> +++ b/crt/riscv32/crti.s
> @@ -0,0 +1,11 @@
> +.section .init
> +.global _init
> +.type _init,%function
> +_init:
> +        ret
> +
> +.section .fini
> +.global _fini
> +.type _fini,%function
> +_fini:
> +        ret
> diff --git a/crt/riscv32/crtn.s b/crt/riscv32/crtn.s
> new file mode 100644
> index 0000000..e69de29

It looks like these are not used, right?

> diff --git a/include/elf.h b/include/elf.h
> index c229735..ec2e8fd 100644
> --- a/include/elf.h
> +++ b/include/elf.h
> @@ -3164,6 +3164,62 @@ enum
>  #define R_BPF_NONE		0
>  #define R_BPF_MAP_FD		1
>  
> +#define R_RISCV_NONE            0
> +#define R_RISCV_32              1
> +#define R_RISCV_64              2
> +#define R_RISCV_RELATIVE        3
> +#define R_RISCV_COPY            4
> +#define R_RISCV_JUMP_SLOT       5
> +#define R_RISCV_TLS_DTPMOD32    6
> +#define R_RISCV_TLS_DTPMOD64    7
> +#define R_RISCV_TLS_DTPREL32    8
> +#define R_RISCV_TLS_DTPREL64    9
> +#define R_RISCV_TLS_TPREL32     10
> +#define R_RISCV_TLS_TPREL64     11
> +
> +#define R_RISCV_BRANCH          16
> +#define R_RISCV_JAL             17
> +#define R_RISCV_CALL            18
> +#define R_RISCV_CALL_PLT        19
> +#define R_RISCV_GOT_HI20        20
> +#define R_RISCV_TLS_GOT_HI20    21
> +#define R_RISCV_TLS_GD_HI20     22
> +#define R_RISCV_PCREL_HI20      23
> +#define R_RISCV_PCREL_LO12_I    24
> +#define R_RISCV_PCREL_LO12_S    25
> +#define R_RISCV_HI20            26
> +#define R_RISCV_LO12_I          27
> +#define R_RISCV_LO12_S          28
> +#define R_RISCV_TPREL_HI20      29
> +#define R_RISCV_TPREL_LO12_I    30
> +#define R_RISCV_TPREL_LO12_S    31
> +#define R_RISCV_TPREL_ADD       32
> +#define R_RISCV_ADD8            33
> +#define R_RISCV_ADD16           34
> +#define R_RISCV_ADD32           35
> +#define R_RISCV_ADD64           36
> +#define R_RISCV_SUB8            37
> +#define R_RISCV_SUB16           38
> +#define R_RISCV_SUB32           39
> +#define R_RISCV_SUB64           40
> +#define R_RISCV_GNU_VTINHERIT   41
> +#define R_RISCV_GNU_VTENTRY     42
> +#define R_RISCV_ALIGN           43
> +#define R_RISCV_RVC_BRANCH      44
> +#define R_RISCV_RVC_JUMP        45
> +#define R_RISCV_RVC_LUI         46
> +#define R_RISCV_GPREL_I         47
> +#define R_RISCV_GPREL_S         48
> +#define R_RISCV_TPREL_I         49
> +#define R_RISCV_TPREL_S         50
> +#define R_RISCV_RELAX           51
> +#define R_RISCV_SUB6            52
> +#define R_RISCV_SET6            53
> +#define R_RISCV_SET8            54
> +#define R_RISCV_SET16           55
> +#define R_RISCV_SET32           56
> +#define R_RISCV_32_PCREL        57
> +
>  #ifdef __cplusplus
>  }
>  #endif

This should be its own patch independent of the port; I can commit it
earlier.

> diff --git a/src/thread/riscv32/syscall_cp.s b/src/thread/riscv32/syscall_cp.s
> new file mode 100644
> index 0000000..71bf6d3
> --- /dev/null
> +++ b/src/thread/riscv32/syscall_cp.s
> @@ -0,0 +1,29 @@
> +.global __cp_begin
> +.hidden __cp_begin
> +.global __cp_end
> +.hidden __cp_end
> +.global __cp_cancel
> +.hidden __cp_cancel
> +.hidden __cancel
> +.global __syscall_cp_asm
> +.hidden __syscall_cp_asm
> +.type __syscall_cp_asm, %function
> +__syscall_cp_asm:
> +__cp_begin:
> +        lw t0, 0(a0)
> +        bnez t0, __cp_cancel
> +
> +        mv t0, a1
> +        mv a0, a2
> +        mv a1, a3
> +        mv a2, a4
> +        mv a3, a5
> +        mv a4, a6
> +        mv a5, a7
> +        lw a6, 0(sp)
> +        mv a7, t0
> +        scall
> +__cp_cancel:
> +        ret
> +__cp_end:
> +        j __cancel

The labels here are backwards. __cp_end must point immediately after
the syscall instruction, and __cp_end needs to jump to __cancel.

> diff --git a/src/thread/riscv64/syscall_cp.s b/src/thread/riscv64/syscall_cp.s
> new file mode 100644
> index 0000000..c745b32
> --- /dev/null
> +++ b/src/thread/riscv64/syscall_cp.s
> @@ -0,0 +1,29 @@
> +.global __cp_begin
> +.hidden __cp_begin
> +.global __cp_end
> +.hidden __cp_end
> +.global __cp_cancel
> +.hidden __cp_cancel
> +.hidden __cancel
> +.global __syscall_cp_asm
> +.hidden __syscall_cp_asm
> +.type __syscall_cp_asm, %function
> +__syscall_cp_asm:
> +__cp_begin:
> +        ld t0, 0(a0)
> +        bnez t0, __cp_cancel
> +
> +        mv t0, a1
> +        mv a0, a2
> +        mv a1, a3
> +        mv a2, a4
> +        mv a3, a5
> +        mv a4, a6
> +        mv a5, a7
> +        ld a6, 0(sp)
> +        mv a7, t0
> +        scall
> +__cp_cancel:
> +        ret
> +__cp_end:
> +        j __cancel
> -- 
> 2.10.0
> 

Likewise here.

Rich

Powered by blists - more mailing lists

Your e-mail address:

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.