• 第8周课下作业1(补)


    第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)
    
    
  • 相关阅读:
    CSS3实现投影效果
    @font-face使用在线字体
    JS全局对象的属性
    const命令声明变量应注意的几点
    IDEA设置不区分大小写提示
    分布式ID生成-雪花算法
    项目Git分支管理规范
    IDEA使用Mybatis插件 MyBatisCodeHelper-Pro
    解决码云出现git@gitee.com: Permission denied (publickey).
    安装RabbitMQ,一直提示Erlang版本过低
  • 原文地址:https://www.cnblogs.com/clever-universe/p/8004522.html
Copyright © 2020-2023  润新知