第8周课下作业1(补)

(蓝墨云上未提交,课下补的)

1 完成家庭作业4.47,4.48,4.49
2 相应代码反汇编成X86-64汇编
3 把上述X86-64汇编翻译成Y86汇编,并给出相应机器码

4.47

用指针引用数组元素实现冒泡排序:

void bubble_a(long *data,long count)
  {
       long i,last,t;
       for(last = count-1;last>0;last--)
       {
           for(i = 0;i<last;i++)
           {
              if(*(data+i+1)<*(data+i))
              {
                  t=*(data+i+1);
                  *(data+i+1)=*(data+i);
                  *(data+i)=t;
              }
          }
      }
  }

测试结果:

image

这个函数和测试代码组成的Y86-64程序:

首先通过分步编译,得到对应的X86汇编程序,再将x86(Bubble_sort.s) 手动翻译为Y86(Bubble_sort.ys)(代码在这里),注意y86与x86的不同之处(见书上P252):

  1. Y86中要将常数加载到寄存器再进行计算,它在算术指令中不能使用立即数。
  2. 要实现从内存读取一个数值并将其与一个寄存器相加,Y86需要两条指令,先将内存中的数装到寄存器里。
  3. Y86的整数操作指令会设置条件码,不需要testq指令,直接使用跳转指令。
  4. 由于Y86-64指令集中所以操作都以8个字节为单位,所以在转换“movl,addl”这些四字节指令时要注意进行符号拓展。

4.48

修改4.47的代码要求不使用跳转,最多使用三次条件传送。

我重新复习并详读了P145——用条件传送实现条件分支。

  • 条件传送的核心是:计算一个条件操作的两种结果,然后再根据条件是否满足从中选取一个。
  • X86-64上可用的条件传送指令具体见P147图3-18
  • 处理器执行条件传送指令:读源值(内存或寄存器),检查条件码,然后要么更新目的寄存器,要么保持不变。

对于这道题,要实现6~11行冒泡排序的测试与交换,且求不使用跳转,最多使用三次条件传送。

  1. 首先必须要看懂X86汇编代码,找到测试与交换这段C程序对应的x86汇编代码,通过我对汇编代码一行行的努力仔细分析,最终找到了对应汇编代码:

    leaq	8(%rdi,%rax,8), %rsi
	movq	(%rsi), %rcx          #从内存装入dada[i]到%rcx
	leaq	(%rdi,%rax,8), %rdx
	movq	(%rdx), %r8           #从内存装入dada[i+1]到%r8
	cmpq	%r8, %rcx
	jge	.L3                       #如果%r8>=%rcx,即dada[i+1]>=dada[i],跳转到.L3改变i值进入下一次循环。
	movq	%r8, (%rsi)           
	movq	%rcx, (%rdx)        #这里是两数交换的汇编代码,只需将寄存器里的值交叉传回内存,不需要借助第三方。
	

显然这里用了一次跳转,根据条件传送指令使用规则,可以这样改写:

  • 不管前面怎么写,最终是一定要从寄存器传回内存。
  • 考虑用条件传送cmovnge(有符号<),当%r8<%rcx,即dada[i+1]<dada[i]时,从内存交叉传到寄存器。
  • 再从寄存器对应传回内存。
  • 这样使用了两次条件传送。
    leaq	8(%rdi,%rax,8), %rsi
	movq	(%rsi), %rcx          
	leaq	(%rdi,%rax,8), %rdx
	movq	(%rdx), %r8
	
	cmpq	%r8, %rcx
	cmovnge (%rsi),%r8
	cmpq	%r8, %rcx
	cmovnge (%rdx),%rcx
	
	movq	%r8, (%rdx)           
	movq	%rcx, (%rsi)
  

4.49

修改4.47的代码要求不使用跳转,最多使用一次条件传送。

这里的分析与4.48同理。需要考虑的是如何将上一题中两次条件传送合并为一次条件传送

我注意到两次条件传送的条件都是同一个,可以这样考虑,虽然这是在汇编程序里,实现两数交换的方式是,是在寄存器和内存之间交叉传送

但我们不妨考虑在高级语言里实现两数交换的方式,即借助第三个变量%r9,这样只需在最后一步交换时,判断是否传送,即仅一次条件传送。

    leaq	8(%rdi,%rax,8), %rsi
	movq	(%rsi), %rcx          
	leaq	(%rdi,%rax,8), %rdx
	movq	(%rdx), %r8
	
	movq    %rcx, %r9
	movq    %r8, %rcx
	
	cmpq	%r8, %r9
	cmovnge %r9,%r8
	
	movq	%r8, (%rdx)           
	movq	%9, (%rsi)

posted on 2017-12-08 11:17  20155225江智宇  阅读(255)  评论(1编辑  收藏  举报