https://godbolt.org/g/WAq2MM汇编翻译网站

A note on register use

image.png

Addressing modes

image.pngimage.png
(float )ptr后
image.pngimage.png
ptr[7]后
image.pngimage.png
ptr = (ptr + 1)后
image.pngimage.png

Signed/unsigned arithmetic

image.pngimage.png
int和unsgined int汇编是一样的,

Lea, multiplication by a constant

image.pngimage.png
可以直接用lea指令进行算术运算,有时候更方便也更节约资源提升效率,乘法是消耗计算资源最多的几个命令之一,用lea代替是个不错的选择。
image.png
image.pngimage.png
image.pngimage.png
lea作算术运算更多的例子
image.png
image.pngimage.png
因为lea的缩放系数只能取1、2、4、8,所以当乘23时,就没有用lea指令了,而是常规的乘法。
image.png
image.pngimage.png
同样,16超出了lea缩放系数的范围,所以用了移位,移位的代价仍然比乘法小。
image.png
image.pngimage.png
小的不是2的次幂的数字,编译器会想办法用最高校的方式替换乘法.
image.pngimage.png
17用lea凑不出来了,用移位和加法来凑。16 + 1 = 17.
image.pngimage.png
25是个较小的平方数,可以用lea凑出来,x + 4x = 5x,5x + 4*5x = 25x
gcc非常不想用乘法
image.png
image.pngimage.png
14是编译器不得不用乘法的最小的数字

Constant folding 常量折叠

An expression that involves only constants can be evaluated at compile-time and have its result substituted into the generated assembly. This compiler feature
is called constant folding.
大概就是说,如果一个表达式全都由常量组成,那么它会被编译时算出来,代入生成的汇编中。编译器的这种特性叫做constant folding

  1. #include <limits.h>
  2. int abs_val(int x)
  3. {
  4. int sn = x >> (sizeof(int)*CHAR_BIT -1);
  5. return (x ^ sn) - sn;
  6. }
  7. int has_zero_byte(unsigned long val)
  8. {
  9. unsigned long ones = ~0UL/UCHAR_MAX;
  10. unsigned long highs = ones << (CHAR_BIT - 1);
  11. return (((val - ones) & highs) & ~val) != 0;
  12. }
  13. int constant_fold(int x)
  14. {
  15. return 10 + ((22*45 + 48)*13 - 100)*x - 1;
  16. }

image.pngimage.png
如图,汇编代码中,直接代入了这些表达式的值,注意这些值是十进制。

2) Tools

Deadlisting with objdump

objdump -d可以将二进制可执行文件反汇编

GDB commands for live assembly debugging

disassemble

image.png
GDB 的 disassemble命令不加参数可以打印当前正在执行的函数的汇编代码。
image.png

b address和b myfn+8

image.png
image.png
打印出汇编代码及指令地址,就可以看着代码在地址处打断点,或者用函数 + 偏移的方式打断点。

stepi和nexti(si和ni)

image.png
stepi和nexti指令:
image.png
image.png

info reg打印所有寄存器、打印单个寄存器内容、设置寄存器值

image.png
image.png

tui (text user interface)

image.png
image.png
image.png
这时用stepi和nexti就可以直观看到汇编代码的执行

Reading and tracing assembly in GDB

image.png
image.png
image.png
<+67>处,编译器直接算出了字符数组常量的长度,编译成汇编是就直接将长度作为常量代入了汇编代码,而不是在汇编代码执行时进入strlen进行计算,相当于constant folding常量折叠。
image.png
image.png
看不出来count的值从何而来,只有<+91>处有个0x6,猜测编译器在编译时就已经算出来count的值。
image.png

image.png
image.png
代码执行到for循环内,打印局部变量和参数,squared变量是状态,因为squared还未定义。
继续执行到退出for循环,打印局部变量,
image.png
发现 i 消失,而且total变为状态,squared不是状态,因为total已经不再使用了。
二者不能同时为状态。
整个过程都没有number,count变量,所以结合上面的汇编代码可以推断出,编译器编译后,把这两个当作常量对待,直接把他们的值代入了程序的执行
,而不是程序执行时再计算他们的值。

3) Writing assembly

# File: asm.s
# -----------
# These fuctions are implemented in assembly and linked with C code

.section .text

    .type  sample, @function
    .globl sample

sample:
    cmpl    %edi, %esi
    je      .L1
    movl    %esi, %eax
    addl    %edi, %eax
    ret
.L1:
    movl    $22, %eax
    ret




    .type  mine, @function
    .globl mine

mine:
    # this function currently empty, yours to fill in!
    cmpl    %edi, %esi
    jg      .second_bigger
    movl    %edi, %eax
    subl    %esi, %eax
    ret
.second_bigger:
    movl    %esi, %eax
    subl    %edi, %eax
    ret

solution:

# File: asm.s
# -----------
# These fuctions are implemented in assembly and linked with C code

.section .text

    .type  sample, @function
    .globl sample

sample:
    cmpl    %edi, %esi
    je      .L1
    movl    %esi, %eax
    addl    %edi, %eax
    ret
.L1:
    movl    $22, %eax
    ret




    .type  mine, @function
    .globl mine

mine:
    # this function currently empty, yours to fill in!
    #mov $0, %eax

    #make sure upper bits are 0s or 1s depending on sign
    salq $32, %rdi
    salq $32, %rsi
    sarq $32, %rdi
    sarq $32, %rsi

    subq %rsi, %rdi
    movq %rdi, %rax
    cmpq $0, %rax
    jns  .pos
    negl %eax
.pos:
    ret