zoukankan      html  css  js  c++  java
  • Ubuntu x86-64汇编(4) 数值操作指令

    整数乘法指令 Integer Multiplication

    对于有符号数的乘法有特殊的规则, 因此无符号数乘法和有符号数乘法对应着不同的指令mul和imul. 乘法会产生两倍尺寸的数值结果, 即两个n-bit数相乘会产生2n-bit的数. 两个8bit数相乘会产生16bit的数. 对于乘法指令有许多变种, 例如对于带符号乘法, 一些指令能将结果裁剪至和源数值一样的尺寸.

    无符号的乘法 Unsigned Multiplication

    通常这种乘法的格式为

    mul   <src>
    mul   <op8>
    mul   <op16>
    mul   <op32>
    mul   <op64>
    mul   word [wVvar]
    mul   al
    mul   dword [dVar]
    mul   qword [qVar]
    

    src运算数必须是寄存器或内存地址, 不能为立即数. 对于这样的单运算数乘法指令, 在执行时, 会使用A寄存器中对应尺寸的数值(al/ax/eax/rax). 分别对应8bit, 16bit, 32bit, 64bit尺寸的运算数. 乘法的结果会被放置在A寄存器以及D寄存器中. 下面的表格显示了不同尺寸下的无符号乘法及其结果
    Byte: ax  = al * <src>
    Word:  dx:ax  = ax * <src>
    Double:  edx:eax = eax * <src>
    Quad:  rdx:rax = rax * <src>

    这样的结果位置组合, 是由于要向下兼容早先的版本, 会让人有些困惑.
    代码例子

    bNumA   db 42
    bNumB   db 73
    wAns    dw 0
    wAns1   dw 0
    wNumA   dw 4321
    wNumB   dw 1234
    dAns2   dd 0
    dNumA   dd 42000
    dNumB   dd 73000
    qAns3   dq 0
    qNumA   dq 420000
    qNumB   dq 730000
    dqAns4  ddq 0
    
    ; wAns = bNumA^2 or bNumA squared
    mov al, byte [bNumA] 
    mul al                  ; result in ax
    mov word [wAns], ax
    
    ; wAns1 = bNumA * bNumB
    mov al, byte [bNumA]
    mul byte [bNumB]        ; result in ax
    mov word [wAns1], ax 
    
    ; dAns1 = wNumA * wNumB
    mov ax, word [wNumA]
    mul word [wNumB]        ; result in dx:ax
    mov word [dAns1], ax
    mov word [dAns1+2], dx
    
    ; qAns3 = dNumA * dNumB
    mov eax, dword [dNumA]
    mul dword [dNumB]       ; result in edx:eax
    mov dword [qAns3], eax 
    mov dword [qAns3+4], edx
    
    ; dqAns4 = qNumA * qNumB
    mov rax, qword [qNumA]
    mul qword [qNumB]       ; result in rdx:rax
    mov qword [dqAns4], rax
    mov qword [dqAns4+8], rdx
    

    带符号数乘法 Signed Multiplication

    带符号数的乘法允许更大范围的运算数和尺寸. 通常的格式为

    imul  <src>
    imul  <dest>, <src/imm32>
    imul  <dest>, <src>, <imm32>
    imul  <op8>
    imul  <op16>
    imul  <op32>
    imul  <op64>
    imul  <reg16>, <op16/imm>
    imul  <reg32>, <op32/imm>
    imul  <reg64>, <op64/imm>
    imul  <reg16>, <op16>, <imm>
    imul  <reg32>, <op32>, <imm>
    imul  <reg64>, <op64>, <imm>
    imul  ax, 17
    imul  al
    imul  ebx, dword [dVar]
    imul  rbx, dword [dVar], 791
    imul  rcx, qword [qVar]
    imul  qword [qVar]
    

    所有的格式中, dest运算数都必须是寄存器, 并且所有的运算数都不能为byte. 当使用单个运算数时, imul的格式和mul是一致的. 当使用两个运算数时, 相乘的是src和dest运算数, 并且结果会存放在desc运算数, 覆盖原值. 立即数的尺寸受src运算数的限制, 可以是double word(32bit), 甚至quadword(64bit), 运算结果被裁剪为dest的尺寸后存放在desc. desc不支持8bit的运算数.

    代码例子

    wNumA dw 1200
    wNumB dw ­2000
    wAns1 dw 0
    wAns2 dw 0
    dNumA dd 42000
    dNumB dd ­13000
    dAns1 dd 0
    dAns2 dd 0
    qNumA dq 120000
    qNumB dq ­230000
    qAns1 dq 0
    qAns2 dq 0
    
    ; wAns1 = wNumA * ­13
    mov  ax, word [wNumA]
    imul ax, ­13           ; result in ax
    mov  word [wAns1], ax
    
    ; wAns2 = wNumA * wNumB
    mov  ax, word [wNumA]
    imul ax, word [wNumB] ; result in ax
    mov  word [wAns2], ax
    
    ; dAns1 = dNumA * 113
    mov  eax, dword [dNumA]
    imul eax, 113         ; result in eax
    mov  dword [dAns1], eax
    
    ; dAns2 = dNumA * dNumB
    mov  eax, dword [dNumA]
    imul eax, dword [dNumB]  ; result in eax
    mov  dword [dAns2], eax
    
    ; qAns1 = qNumA * 7096
    mov  rax, qword [qNumA]
    imul rax, 7096           ; result in rax
    mov  qword [qAns1], rax
    
    ; qAns2 = qNumA * qNumB
    mov  rax, qword [qNumA]
    imul rax, qword [qNumB]  ; result in rax
    mov  qword [qAns2], rax
    
    ; 计算 qAns1 = qNumA * 7096 的另一种方式是:
    ; qAns1 = qNumA * 7096
    mov  rcx, qword [qNumA]
    imul rbx, rcx, 7096      ; result in rax
    mov  qword [qAns1], rax
    

    .

    整数除法指令 Integer Division

    对有符号数和无符号数, 也有不同的除法指令div和idiv. 指令格式

    div <src>
    div <op8>
    div <op16>
    div <op32>
    div <op64>
    div   word [wVvar]
    div   bl
    div   dword [dVar]
    div   qword [qVar]
    
    idiv <src>
    idiv <op8>
    idiv <op16>
    idiv <op32>
    idiv <op64>
    idiv  word [wVvar]
    idiv  bl
    idiv  dword [dVar]
    idiv  qword [qVar]
    

    因为 dividend / divisor = quotient, 除法要求被除数的尺寸大于除数. 例如要除以8bit除数, 被除数必须为16bit. 和乘法一样, 运算中需要结合使用A和D寄存器, 这也是为了与旧的架构相兼容. 除法中A和D寄存器的组合如下:
    Byte Divide:        ax for 16-bits
    Word Divide:        dx:ax for 32-bits
    Double-word divide: edx:eax for 64-bits
    Quadword Divide:    rdx:rax for 128-bits

    Byte: al = ax / <src> , rem in ah
    Word: ax = dx:ax / <src>, rem in dx
    Double: eax = eax / <src>, rem in edx
    Quad:  rax = rax / <src>, rem in rdx

    正确地设置被除数是问题的关键, 对于word, double word, quadword类型的被除数, 都需要用到A和D寄存器. 如果之前刚刚进行过乘法运算, 那么A和D就正好已经被赋值. 否则当前数值就需要升级成较大尺寸并将上半部分放到D寄存器. 对于无符号数, 高地址部分总是全为零, 而对于有符号数, 则需要根据之前的说明对高地址部分进行扩展.出书可以是一个内存地址或寄存器, 但是不能为立即数. 另外, 结果将被放置在A寄存器(al/ax/eax/rax), 余数部分会被放置在ah, dx, edx, 或者rdx 寄存器. 对更大尺寸的被除数的使用与乘法指令一样, 对于简单的除法, 要使用合适的转换保证数值被正确的初始化, 对于无符号数相除, 要将高地址部分置零, 对于有符号数相除, 要根据实际情况置零或置一. 零作为除数参与除法运算将会导致程序崩溃, 要避免零除数.
    代码例子

    bNumA db 63
    bNumB db 17
    bNumC db 5
    bAns1 db 0
    bAns2 db 0
    bRem2 db 0
    bAns3 db 0
    wNumA dw 4321
    wNumB dw 1234
    wNumC dw 167
    wAns1 dw 0
    wAns2 dw 0
    wRem2 dw 0
    wAns3 dw 0
    dNumA dd 42000
    dNumB dd ­3157
    dNumC dd ­293
    dAns1 dd 0
    dAns2 dd 0
    dRem2 dd 0
    dAns3 dd 0
    qNumA dq 730000
    qNumB dq ­13456
    qNumC dq ­1279
    qAns1 dq 0
    qAns2 dq 0
    qRem2 dq 0
    qAns3 dq 0
    
    ; ----
    ; example byte operations, unsigned
    
    ; bAns1 = bNumA / 3 (unsigned)
    mov  al, byte [bNumA]
    mov  ah, 0
    mov  bl, 3
    div  bl            ; al = ax / 3
    mov  byte [bAns1], al
    
    ; bAns2 = bNumA / bNumB (unsigned)
    mov  ax, 0
    mov  al, byte [bNumA]
    div  byte [bNumB]       ; al = ax / bNumB
    mov  byte [bAns2], al
    mov  byte [bRem2], ah   ; ah = ax % bNumB
    
    ; bAns3 = (bNumA * bNumC) / bNumB (unsigned)
    mov  al, byte [bNumA]
    mul  byte [bNumC]       ; result in al
    div  byte [bNumB]       ; al = ax / bNumB
    mov  byte [bAns3], al
    
    ; ----
    ; example word operations, unsigned
    
    ; wAns1 = wNumA / 5 (unsigned)
    mov  ax, word [wNumA]
    mov  dx, 0
    mov  bx, 5
    div  bx                 ; ax = dx:ax / 5
    mov  word [wAns1], ax
    
    ; wAns2 = wNumA / wNumB (unsigned)
    mov  dx, 0
    mov  ax, word [wNumA]
    div  word [wNumB]       ; ax = dx:ax / wNumB
    mov  word [wAns2], ax
    mov  word [wRem2], dx
    
    ; wAns3 = (wNumA * wNumC) / wNumB (unsigned)
    mov  ax, word [wNumA]
    mul  word [wNumC]       ; result in dx:ax
    div  word [wNumB]       ; ax = dx:ax / wNumB
    mov  word [wAns3], ax
    
    ; ----
    ; example double­word operations, signed
    
    ; dAns1 = dNumA / 7 (signed)
    mov  eax, dword [dNumA]
    cdq                     ; eax → edx:eax
    mov  ebx, 7
    idiv ebx                ; eax = edx:eax / 7
    mov  dword [dAns1], eax
    
    ; dAns2 = dNumA / dNumB (signed)
    mov  eax, dword [dNumA]
    cdq                     ; eax → edx:eax
    idiv dword [dNumB]      ; eax = edx:eax/dNumB
    mov  dword [dAns2], eax
    mov  dword [dRem2], edx ; edx = edx:eax%dNumB
    
    ; dAns3 = (dNumA * dNumC) / dNumB (signed)
    mov  eax, dword [dNumA]
    imul dword [dNumC]      ; result in edx:eax
    idiv dword [dNumB]      ; eax = edx:eax/dNumB
    mov  dword [dAns3], eax
    
    ; ----
    ; example quadword operations, signed
    
    ; qAns1 = qNumA / 9 (signed)
    mov  rax, qword [qNumA]
    cqo                     ; rax → rdx:rax
    mov  rbx, 9
    idiv rbx                ; eax = edx:eax / 9
    mov  qword [qAns1], rax
    
    ; qAns2 = qNumA / qNumB (signed)
    mov  rax, qword [qNumA]
    cqo                     ; rax → rdx:rax
    idiv qword [qNumB]      ; rax = rdx:rax/qNumB
    mov  qword [qAns2], rax
    mov  qword [qRem2], rdx ; rdx = rdx:rax%qNumB
    
    ; qAns3 = (qNumA * qNumC) / qNumB (signed)
    mov  rax, qword [qNumA]
    imul qword [qNumC]      ; result in rdx:rax
    idiv qword [qNumB]      ; rax = rdx:rax/qNumB
    mov  qword [qAns3], rax
    

    逻辑指令 Logical Instructions

    基础逻辑指令

    与操作
    and   <dest>, <src>
    and   ax, bx
    and   rcx, rdx
    and   eax, dword [dNum]
    and   qword [qNum], rdx
    
    或操作
    or   <dest>, <src>
    or   ax, bx
    or   rcx, rdx
    or   eax, dword [dNum]
    or   qword [qNum], rdx
    
    或非操作
    xor <dest>, <src>
    xor   ax, bx
    xor   rcx, rdx
    xor   eax, dword [dNum]
    xor   qword [qNum], rdx
    
    非操作
    not   <op>
    not   bx
    not   rdx
    not   dword [dNum]
    not   qword [qNum]
    

    移位操作

    逻辑左移, 从右边补零. <imm>和cl 取值必须在1~64之间, <dest>不能是立即数

    shl   <dest>, <imm>
    shl   <dest>, cl
    shl   ax, 8
    shl   rcx, 32
    shl   eax, cl
    shl   qword [qNum], cl
    

    逻辑右移, 从左边补零. <imm>和cl 取值必须在1~64之间, <dest>不能是立即数

    shr   <dest>, <imm>
    shr   <dest>, cl
    shr   ax, 8
    shr   rcx, 32
    shr   eax, cl
    shr   qword [qNum], cl
    

    算术移位将运算数作为一个有符号数进行处理并保留符号. 但是算数移位使用的是四舍五入而标准除法使用的是裁剪, 所以不能用算术移位代替除法指令

    算术左移

    sal   <dest>, <imm>
    sal   <dest>, cl
    sal   ax, 8
    sal   rcx, 32
    sal   eax, cl
    sal   qword [qNum], cl
    

    算术右移

    sar   <dest>, <imm>
    sar   <dest>, cl
    sar   ax, 8
    sar   rcx, 32
    sar   eax, cl
    sar   qword [qNum], cl
    

    循环移位指令只是移位方向不同,它们移出的位不仅要进入CF,而且还要填补空出的位

    循环左移

    rol   <dest>, <imm>
    rol   <dest>, cl
    rol   ax, 8
    rol   rcx, 32
    rol   eax, cl
    rol   qword [qNum], cl
    

    循环右移

    ror   <dest>, <imm>
    ror   <dest>, cl
    ror   ax, 8
    ror   rcx, 32
    ror   eax, cl
    ror   qword [qNum], cl
    

    控制指令 Control Instructions

    .

    .

  • 相关阅读:
    [模板] 循环数组的最大子段和
    [最短路][几何][牛客] [国庆集训派对1]-L-New Game
    [洛谷] P1866 编号
    1115 Counting Nodes in a BST (30 分)
    1106 Lowest Price in Supply Chain (25 分)
    1094 The Largest Generation (25 分)
    1090 Highest Price in Supply Chain (25 分)
    树的遍历
    1086 Tree Traversals Again (25 分)
    1079 Total Sales of Supply Chain (25 分 树
  • 原文地址:https://www.cnblogs.com/milton/p/9102982.html
Copyright © 2011-2022 走看看