Architecture Lab:part A 实现sum_list/rsum_list/copy_block/熟悉Y86-64指令

 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: