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

    .

    .

  • 相关阅读:
    IIS6.0服务器架站无法访问解决方案总结
    DNN中做支持多语言的模块
    在dotnetnuke中创建 parent portal
    DNN,Rainbow资源
    2005年岁末,各种主流CMS系统的比较和汇总
    在DNN中获取所有模块信息
    学习dnn的新资源,sooooooooo great!!
    DNN的电子商务模块
    DNN学习笔记
    也学ASP.NET 2.0 AJAX 之二:使用Timer控件
  • 原文地址:https://www.cnblogs.com/milton/p/9102982.html
Copyright © 2011-2022 走看看