Loading

MIT 6.S081 操作系统 LAB4:Traps

Lab: traps

RISC-V assembly

有关RISC-V的汇编,分析call.c中的代码

call.c:

int g(int x) {
  return x+3;
}

int f(int x) {
  return g(x);
}

void main(void) {
  printf("%d %d\n", f(8)+1, 13);
  exit(0);
}

call.asm:

int g(int x) {
0:	1141                	addi	sp,sp,-16
2:	e422                	sd	s0,8(sp)
4:	0800                	addi	s0,sp,16
return x+3;
}
6:	250d                	addiw	a0,a0,3
8:	6422                	ld	s0,8(sp)
a:	0141                	addi	sp,sp,16
c:	8082                	ret

000000000000000e <f>:

int f(int x) {
e:	1141                	addi	sp,sp,-16
10:	e422                	sd	s0,8(sp)
12:	0800                	addi	s0,sp,16
return g(x);
}
14:	250d                	addiw	a0,a0,3
16:	6422                	ld	s0,8(sp)
18:	0141                	addi	sp,sp,16
1a:	8082                	ret

000000000000001c <main>:

void main(void) {
1c:	1141                	addi	sp,sp,-16
1e:	e406                	sd	ra,8(sp)
20:	e022                	sd	s0,0(sp)
22:	0800                	addi	s0,sp,16
printf("%d %d\n", f(8)+1, 13);
24:	4635                	li	a2,13
26:	45b1                	li	a1,12
28:	00000517          	auipc	a0,0x0
2c:	7c050513          	addi	a0,a0,1984 # 7e8 <malloc+0xea>
30:	00000097          	auipc	ra,0x0
34:	610080e7          	jalr	1552(ra) # 640 <printf>
exit(0);
38:	4501                	li	a0,0
3a:	00000097          	auipc	ra,0x0
3e:	27e080e7          	jalr	638(ra) # 2b8 <exit>

Which registers contain arguments to functions? For example, which register holds 13 in main's call to printf?

a0保存返回值,a1保存参数12,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.)

没有具体的调用,编译器优化成了内联函数,直接产生函数调用的结果

At what address is the function printf located?

0x640
30: 00000097 auipc ra,0x0将pc的值放入ra,此时ra的值为0x30
34: 610080e7 jalr 1552(ra) # 640 <printf>相对寻址,1552+48=1600=0x640

What value is in the register ra just after the jalr to printf in main?

ra保存返回地址,故是调用printf后的下一条指令地址:0x38

Run the following code. What is the output? Here's an ASCII table that maps bytes to characters.

unsigned int i = 0x00646c72;
printf("H%x Wo%s", 57616, &i);

RISC-V是小端,低地址保存低位数据
57616=0xe110
在ASCII中,72对应r,6c对应l,64对应d
故输出为He110 World
如果RISC-V是大端,则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);

y的输出是未定义的,取决于定义寄存器的值

Backtrace

For debugging it is often useful to have a backtrace: a list of the function calls on the stack above the point at which the error occurred.

取出fp栈帧指针,不断往前读取,因为xv6分配栈是按页对齐的,所以读到页对齐循环结束
栈帧布局如下:

fp-8的地址为return address,fp-16为上一个栈帧的地址

void backtrace()
{
  printf("backtrace:\n");
  uint64 fp=r_fp();
  while(PGROUNDDOWN(fp)!=fp)
  {
    uint64 addr=*((uint64*)(fp-8));
    printf("%p\n",addr);
    fp=*((uint64*)(fp-16));
  }
}

Alarm

实现一个定时器,每隔一定数量的cpu时钟,执行handler函数

修改proc结构体

//alarm
  int interval;
  void (*fn) ();//handler
  int count;
  int handling;//表示是否正在执行handler函数
  struct trapframe save_info;//保存信息

系统调用

sigalarm设置定时器

uint64
sys_sigalarm(void)
{
  struct proc *p = myproc();
  int interval;
  void(*fn)();
  if(argint(0, &interval) < 0)
    return -1;
  if(argaddr(1, (uint64*)&fn) < 0)
    return -1;
  p->interval=interval;
  p->fn=fn;
  p->count=interval;
  return 0;
}

sigreturn将保存下来的trapframe还原回去,还原寄存器现场

uint64
sys_sigreturn(void)
{
  struct proc *p = myproc();
  p->handling=0;
  *(p->trapframe)=p->save_info;
  return 0;
}

处理时钟中断

每个时钟中断,进行相应的处理

// give up the CPU if this is a timer interrupt.
  if(which_dev == 2)
  {
    if(p->interval!=0&&!p->handling)
    {
      if(--p->count==0)
      {
        p->count=p->interval;
        p->handling=1;
        p->save_info=*(p->trapframe);
        p->trapframe->epc=(uint64)p->fn;
      }
    }
    yield();
  }

思路有以下:

  • 通过判断interval是否==0决定是否设置了定时器
  • 判断p->handling,如果正在执行handler则不改变闹钟时间
  • 进入handler前要保存当前trapframe,方便在sigreturn中还原
  • 改变pc的值为handler的地址,执行处理函数

test

posted @ 2021-12-27 23:43  traver  阅读(152)  评论(0编辑  收藏  举报