aboutsummaryrefslogtreecommitdiff
path: root/glibc/sysdeps/unix/sysv/linux/riscv/makecontext.c
blob: bbbdbf33385b46c9d0a67922d042bab82c15e3d1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <sysdep.h>
#include <sys/asm.h>
#include <sys/ucontext.h>
#include <stdarg.h>
#include <assert.h>

void __makecontext (ucontext_t *ucp, void (*func) (void), int argc,
		    long a0, long a1, long a2, long a3, long a4, ...)
{
  extern void __start_context(void) attribute_hidden;
  long i, sp;
  va_list vl;

  va_start(vl, a4);
  assert(REG_NARGS == 8);

  /* Set up the stack. */
  sp = ((long)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size) & ALMASK;

  /* Put args in a0-a7, then put any remaining args on the stack. */
  ucp->uc_mcontext.gregs[REG_A0 + 0] = a0;
  ucp->uc_mcontext.gregs[REG_A0 + 1] = a1;
  ucp->uc_mcontext.gregs[REG_A0 + 2] = a2;
  ucp->uc_mcontext.gregs[REG_A0 + 3] = a3;
  ucp->uc_mcontext.gregs[REG_A0 + 4] = a4;
  if (__builtin_expect(argc > 5, 0))
    {
      long reg_args = argc < REG_NARGS ? argc : REG_NARGS;
      sp = (sp - (argc - reg_args) * sizeof(long)) & ALMASK;
      for (i = 5; i < reg_args; i++)
        ucp->uc_mcontext.gregs[REG_A0 + i] = va_arg(vl, long);
      for (i = 0; i < argc - reg_args; i++)
        ((long*)sp)[i] = va_arg(vl, long);
    }

  ucp->uc_mcontext.gregs[REG_S0] = (long)ucp->uc_link;
  ucp->uc_mcontext.gregs[REG_SP] = sp;
  ucp->uc_mcontext.gregs[REG_PC] = (long)func;
  ucp->uc_mcontext.gregs[REG_RA] = (long)&__start_context;

  va_end(vl);
}

weak_alias (__makecontext, makecontext)