RISC-V assembly
Which registers contain arguments to functions? For example, which register holds 13 in main's call to printf?
根据RISC-V函数调用规范,函数的前8个参数使用a0-a7寄存器传递。
当main函数调用printf函数时,a2寄存器保存13
Where is the call to function f in the assembly code for main? Where is the call to g? (Hint: the compiler may inline functions.)
通过 li a1,12 可知,当main函数调用函数 f 时,已经内联了函数 f ,所以可以看到编译器直接将12保存到寄存器a1中
而在函数 f 中,编译器也内联了函数 g 的调用,直接向a0 寄存器加3
At what address is the function printf located?
0x0000000000000642
What value is in the register ra just after the jalr to printf in main?
0x38
Run the following code. What is the output? The output depends on that fact that the RISC-V is little-endian. If the RISC-V were instead big-endian what would you set i
to in order to yield the same output? Would you need to change 57616
to a different value?
unsigned int i = 0x00646c72;
printf("H%x Wo%s", 57616, &i);
输出: He110 World
如果是大端机器,57616 不用变,i 变为 0x726c6400
In the following code, what is going to be printed after 'y='
? (note: the answer is not a specific value.) Why does this happen?
printf("x=%d y=%d", 3);
a2寄存器中的值
Backtrace
void backtrace(void)
{
uint64 ra;
uint64 fp = r_fp();
uint64 up = PGROUNDUP(fp);
printf("backtrace:\n");
while (fp < up)
{
ra = fp - 8;
printf("%p\n",*(uint64*)ra);
fp = *(uint64*)(fp - 16);
}
}
Alarm
struct proc
{
struct spinlock lock;
// p->lock must be held when using these:
enum procstate state; // Process state
void *chan; // If non-zero, sleeping on chan
int killed; // If non-zero, have been killed
int xstate; // Exit status to be returned to parent's wait
int pid; // Process ID
// wait_lock must be held when using this:
struct proc *parent; // Parent process
// these are private to the process, so p->lock need not be held.
uint64 kstack; // Virtual address of kernel stack
uint64 sz; // Size of process memory (bytes)
pagetable_t pagetable; // User page table
struct trapframe *trapframe; // data page for trampoline.S
struct context context; // swtch() here to run process
struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory
char name[16]; // Process name (debugging)
int alarm_interval;
void (*alarm_handler)();
int alarm_ticks;
struct trapframe * alarm_frame;
int alarm_is_returned;
};
void usertrap(void)
{
int which_dev = 0;
if ((r_sstatus() & SSTATUS_SPP) != 0)
panic("usertrap: not from user mode");
// send interrupts and exceptions to kerneltrap(),
// since we're now in the kernel.
w_stvec((uint64)kernelvec);
struct proc *p = myproc();
// save user program counter.
p->trapframe->epc = r_sepc();
if (r_scause() == 8)
{
// system call
if (killed(p))
exit(-1);
// sepc points to the ecall instruction,
// but we want to return to the next instruction.
p->trapframe->epc += 4;
// an interrupt will change sepc, scause, and sstatus,
// so enable only now that we're done with those registers.
intr_on();
syscall();
}
else if ((which_dev = devintr()) != 0)
{
// ok
}
else
{
printf("usertrap(): unexpected scause %p pid=%d\n", r_scause(), p->pid);
printf(" sepc=%p stval=%p\n", r_sepc(), r_stval());
setkilled(p);
}
if (killed(p))
exit(-1);
// give up the CPU if this is a timer interrupt.
if (which_dev == 2)
{
p->alarm_ticks++;
if (p->alarm_interval != 0 && p->alarm_ticks == p->alarm_interval && p->alarm_is_returned == 1)
{
memmove((void*)p->alarm_frame,(const void*)p->trapframe, sizeof(struct trapframe));
p->trapframe->epc = (uint64)p->alarm_handler;
p->alarm_ticks = 0;
p->alarm_is_returned = 0;
}
yield();
}
usertrapret();
}
static struct proc *
allocproc(void)
{
struct proc *p;
for (p = proc; p < &proc[NPROC]; p++)
{
acquire(&p->lock);
if (p->state == UNUSED)
{
goto found;
}
else
{
release(&p->lock);
}
}
return 0;
found:
p->pid = allocpid();
p->state = USED;
p->alarm_interval = 0;
p->alarm_handler = 0;
p->alarm_ticks = 0;
p->alarm_is_returned = 1;
// Allocate a trapframe page.
if ((p->trapframe = (struct trapframe *)kalloc()) == 0)
{
freeproc(p);
release(&p->lock);
return 0;
}
if ((p->alarm_frame = (struct trapframe *)kalloc()) == 0)
{
freeproc(p);
release(&p->lock);
return 0;
}
// An empty user page table.
p->pagetable = proc_pagetable(p);
if (p->pagetable == 0)
{
freeproc(p);
release(&p->lock);
return 0;
}
// Set up new context to start executing at forkret,
// which returns to user space.
memset(&p->context, 0, sizeof(p->context));
p->context.ra = (uint64)forkret;
p->context.sp = p->kstack + PGSIZE;
return p;
}
// free a proc structure and the data hanging from it,
// including user pages.
// p->lock must be held.
static void
freeproc(struct proc *p)
{
if (p->trapframe)
kfree((void *)p->trapframe);
p->trapframe = 0;
if (p->alarm_frame)
{
kfree((void *)p->alarm_frame);
}
p->alarm_frame = 0;
if (p->pagetable)
proc_freepagetable(p->pagetable, p->sz);
p->pagetable = 0;
p->sz = 0;
p->pid = 0;
p->parent = 0;
p->name[0] = 0;
p->chan = 0;
p->killed = 0;
p->xstate = 0;
p->state = UNUSED;
}
uint64
sys_sigalarm(void)
{
int ticks;
uint64 handler;
struct proc *p = myproc();
argint(0, &ticks);
argaddr(1, &handler);
p->alarm_interval = ticks;
p->alarm_handler = (void*)handler;
p->alarm_ticks = 0;
p->alarm_is_returned = 1;
return 0;
}
uint64
sys_sigreturn(void)
{
struct proc *p = myproc();
p->alarm_ticks = 0;
p->alarm_is_returned = 1;
memmove((void*)p->trapframe,(const void*)p->alarm_frame,sizeof(struct trapframe));
return p->trapframe->a0;
}