Architecture Lab 对应CS:APP的Chap 4——处理器体系结构。Part A要实现三个函数,分别为sum_list/rsum_list/copy_block。建议先得到x86-64指令,然后再转换为Y86-64指令。
准备工作
在misc目录下,键入以下命令用来生成汇编代码。命令执行完毕后会生成examples.o。
gcc -S examples.c
sum_list的Y86-64实现
在examples.o中找到第一个要实现的函数sum_list,如下
sum_list: .LFB0: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq %rdi, -24(%rbp) movq $0, -8(%rbp) jmp .L2 .L3: movq -24(%rbp), %rax movq (%rax), %rax addq %rax, -8(%rbp) movq -24(%rbp), %rax movq 8(%rax), %rax movq %rax, -24(%rbp) .L2: cmpq $0, -24(%rbp) jne .L3 movq -8(%rbp), %rax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc
可见,这个代码是将局部变量存在栈帧上,而书上的x86代码并不是这么复杂,而是直接把值存在某寄存器中,进行加减操作。那么我们也来做一些等价转换,转换后的结果如下代码:
sum_list: .LFB0: movq $0, %rax jmp .L2 .L3: addq (%rdi), %rax movq 8(%rdi), %rdi .L2: cmpq $0, %rdi jne .L3 ret
然后根据Y86-64的规则,进行改写。
sum_list:
.LFB0:
movq $0, %rax -> irmovq $0, %rax
jmp .L2
.L3:
addq (%rdi), %rax -> mrmovq (%rdi), %r8 addq %r8, %rax
movq 8(%rdi), %rdi ->mrmovq 8(%rdi), %rdi
.L2:
cmpq $0, %rdi ->andq %rdi, %rdi
jne .L3
ret
即为
sum_list: .LFB0: irmovq $0, %rax jmp .L2 .L3: mrmovq (%rdi), %r8 addq %r8, %rax mrmovq 8(%rdi), %rdi .L2: andq %rdi, %rdi jne .L3 ret
这只是一个函数,现需要把它写为完整的程序。根据书上page 252的代码4-7,补上main函数、调用main函数的语段、数据段即可。如下:
.pos 0 irmovq stack,%rsp call main halt # 这是archlab.pdf中给出的测试样例 .align 8 ele1: .quad 0x00a .quad ele2 ele2: .quad 0x0b0 .quad ele3 ele3: .quad 0xc00 .quad 0 main: irmovq ele1, %rdi call sum_list ret sum_list: LFB0: irmovq $0, %rax jmp L2 L3: mrmovq (%rdi), %r8 addq %r8, %rax mrmovq 8(%rdi), %rdi L2: andq %rdi, %rdi jne L3 ret .pos 0x200 stack:
用yas得到.yo文件,再用yis运行.yo文件,得到各个寄存器运行后的值,如下。
sum_list函数完成。
rsum_list的Y86-64实现
在examples.o中找到第二个要实现的函数rsum_list,如下:
rsum_list: .LFB1: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 subq $32, %rsp movq %rdi, -24(%rbp) cmpq $0, -24(%rbp) jne .L6 movl $0, %eax jmp .L7 .L6: movq -24(%rbp), %rax movq (%rax), %rax movq %rax, -16(%rbp) movq -24(%rbp), %rax movq 8(%rax), %rax movq %rax, %rdi call rsum_list movq %rax, -8(%rbp) movq -16(%rbp), %rdx movq -8(%rbp), %rax addq %rdx, %rax .L7: leave .cfi_def_cfa 7, 8 ret .cfi_endproc
同样,递归产生的n个栈帧中存了两个参数和求得的和。由于是递归,是否寄存器不可简化?
答案是可以简化的,栈帧上只存求得的和,不存两个参数。
rsum_list: .LFB1: cmpq $0, %rdi jne .L6 movl $0, %eax jmp .L7 .L6: movq (%rdi), %rax push %rax movq 8(%rdi), %rdi call rsum_list pop %r8 addq %r8, %rax .L7: ret
把这个简化之后的x86-64代码转换为Y86-64
rsum_list: .LFB1: andq %rdi, %rdi jne .L6 irmovq $0, %rax jmp .L7 .L6: mrmovq (%rdi), %rax push %rax mrmovq 8(%rdi), %rdi call rsum_list pop %r8 addq %r8, %rax .L7: ret
放到刚刚写的框架中即可。
copy_block的Y86-64实现
在examples.o中找到第三个要实现的函数copy_block,如下:
copy_block: .LFB2: .cfi_startproc endbr64 pushq %rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 movq %rsp, %rbp .cfi_def_cfa_register 6 movq %rdi, -24(%rbp) movq %rsi, -32(%rbp) movq %rdx, -40(%rbp) movq $0, -16(%rbp) jmp .L9 .L10: movq -24(%rbp), %rax leaq 8(%rax), %rdx movq %rdx, -24(%rbp) movq (%rax), %rax movq %rax, -8(%rbp) movq -32(%rbp), %rax leaq 8(%rax), %rdx movq %rdx, -32(%rbp) movq -8(%rbp), %rdx movq %rdx, (%rax) movq -8(%rbp), %rax xorq %rax, -16(%rbp) subq $1, -40(%rbp) .L9: cmpq $0, -40(%rbp) jg .L10 movq -16(%rbp), %rax popq %rbp .cfi_def_cfa 7, 8 ret .cfi_endproc
简化代码
copy_block: .LFB2: movq $0, %rax jmp .L9 .L10: movq (%rdi), %r8 leaq 8(%rdi), %rdi movq %r8, (%rsi) leaq 8(%rsi), %rsi xorq %r8, %rax subq $1, %rdx .L9: cmpq $0, %rdx jg .L10 ret
改为Y86-64代码
copy_block: .LFB2: irmovq $1, %r9 # const value irmovq $8, %r10 # const value irmovq $0, %rax jmp .L9 .L10: mrmovq (%rdi), %r8 addq %r10, %rdi rmmovq %r8, (%rsi) addq %r10, %rsi xorq %r8, %rax subq %r9, %rdx .L9: andq %rdx, %rdx jg .L10 ret
新建copy_block.ys
.pos 0 irmovq stack,%rsp call main halt .align 8 # Source block src: .quad 0x00a .quad 0x0b0 .quad 0xc00 # Destination block dest: .quad 0x111 .quad 0x222 .quad 0x333 main: irmovq src, %rdi irmovq dest, %rsi irmovq $3, %rdx call copy_block ret copy_block: LFB2: irmovq $1, %r9 # const value irmovq $8, %r10 # const value irmovq $0, %rax jmp L9 L10: mrmovq (%rdi), %r8 addq %r10, %rdi rmmovq %r8, (%rsi) addq %r10, %rsi xorq %r8, %rax subq %r9, %rdx L9: andq %rdx, %rdx jg L10 ret .pos 0x500 stack: