日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

汇编之浮点数处理(CrackMe003前置知识)

發(fā)布時(shí)間:2025/3/20 编程问答 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 汇编之浮点数处理(CrackMe003前置知识) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 浮點(diǎn)數(shù)的二進(jìn)制表示
      • IEEE二進(jìn)制浮點(diǎn)數(shù)的表示
        • 1.符號位
        • 2.有效數(shù)字
        • 3.有效數(shù)字的精度
      • 階碼
      • 規(guī)格化二進(jìn)制浮點(diǎn)數(shù)
      • 新建IEEE表示
        • 實(shí)數(shù)編碼
      • 單精度數(shù)轉(zhuǎn)換為十進(jìn)制
    • 浮點(diǎn)單元
      • FPU寄存器棧
      • FPU寄存器
      • 專用寄存器
        • 舍入
        • FPU控制字
      • 浮點(diǎn)數(shù)異常
      • 浮點(diǎn)數(shù)指令集
        • 1.初始化(FINIT)
        • 2.浮點(diǎn)數(shù)據(jù)類型
        • 3.加載浮點(diǎn)數(shù)值 FLD
        • FILD
        • 加載常數(shù)
        • 保存浮點(diǎn)數(shù)值(FST FSTP FIST)
      • 算術(shù)運(yùn)算指令
        • FCHS和FABS
        • FADD FADDP FIADD
        • FSUB FSUBP FISUB
        • FMUL FMULP FIMUL
        • FDIV FDIVP FIDIV
      • 比較浮點(diǎn)數(shù)值
        • FCOM FCOMP FCOMPP
        • 條件碼
        • P6處理器的改進(jìn)
      • 讀寫浮點(diǎn)數(shù)值
      • 異常同步

浮點(diǎn)數(shù)的二進(jìn)制表示

十進(jìn)制浮點(diǎn)數(shù)有三個(gè)部分組成:符號,有效數(shù)字和階碼。比如,在-1.23154*105中,符號為負(fù),有效數(shù)字為1.23154,階碼為5

IEEE二進(jìn)制浮點(diǎn)數(shù)的表示

x86處理器使用的三種浮點(diǎn)數(shù)二進(jìn)制存儲(chǔ)格式都是由IEEE標(biāo)準(zhǔn)754-1985——二進(jìn)制浮點(diǎn)運(yùn)算一一所制定。下表列出了他們的特點(diǎn)

精度范圍
單精度32位:1位符號位,8位階碼,23位為有效數(shù)字的小數(shù)部分。大致的規(guī)格化范圍:2-126—2127 也被稱為短實(shí)數(shù)
雙精度64位:1位符號位,11位階碼,52位為有效數(shù)字的小數(shù)部分。大致的規(guī)格化范圍為:2-1022—21023 也被稱為長實(shí)數(shù)
擴(kuò)展雙精度80位:1位符號位,15位階碼,1位為整數(shù)部分,63位為有效數(shù)字的小數(shù)部分。大致的規(guī)格化范圍:2-16382—216383 也被稱為擴(kuò)展實(shí)數(shù)

由于三種格式比較相似,因此本節(jié)將重點(diǎn)關(guān)注單精度格式。

1.符號位

如果符號位為1,則該數(shù)為負(fù);如果符號位為0,則該數(shù)為正。

2.有效數(shù)字

浮點(diǎn)數(shù)的有效數(shù)字由小數(shù)點(diǎn)的左右的十進(jìn)制數(shù)字構(gòu)成。十進(jìn)制的數(shù)123.154用加權(quán)位計(jì)數(shù)法可以表示為下面的累加和形式

123.154=(1x102)+(2x101)+(3x100)+(1x10-1)+(5x10-2)+(4x10-3)

小數(shù)點(diǎn)左邊的數(shù)字的階碼都位正,右邊的數(shù)字階碼都為負(fù)

小數(shù)點(diǎn)右邊數(shù)字還有一種表達(dá)方式,即把他們列為分?jǐn)?shù)之和,其中分母為2的冪,例如:

.1011=1/2+0/4+1/8+1/16=11/16

3.有效數(shù)字的精度

用有限位數(shù)表示的任何浮點(diǎn)數(shù)都無法表示完整的連續(xù)的實(shí)數(shù)。例如:假設(shè)一個(gè)簡單的浮點(diǎn)數(shù)格式有5位有效數(shù)字,那么將無法表示范圍在1.1111-10.000之間的二進(jìn)制數(shù)。比如,二進(jìn)制數(shù)1.11111就需要更精確的有效數(shù)字。將這個(gè)思想擴(kuò)展到IEEE雙精度格式,就會(huì)發(fā)現(xiàn)53位有效數(shù)字無法表示需要54位或更多二進(jìn)制數(shù)值。

階碼

單精度數(shù)用8位無符號整數(shù)存放階碼,引入的偏差為127,因此必須在數(shù)的實(shí)際階碼上再加上127

規(guī)格化二進(jìn)制浮點(diǎn)數(shù)

大多數(shù)二進(jìn)制浮點(diǎn)數(shù)都以規(guī)格化格式存放,以便將有效數(shù)字的精度最大化。給定任意二進(jìn)制浮點(diǎn)數(shù),都可以進(jìn)行規(guī)格化,方法是將小數(shù)點(diǎn)移位,直到小數(shù)點(diǎn)左邊只有一個(gè)1。階碼表示的是二進(jìn)制小數(shù)點(diǎn)向左或向右移動(dòng)的位數(shù)。示例如下:

非規(guī)格化規(guī)格化
1110.11.1101x23
0001011.01x2-4
10100011.010001x2-6

反規(guī)格化數(shù):規(guī)格化操作的逆操作是將二進(jìn)制浮點(diǎn)數(shù)反規(guī)格化。移動(dòng)二進(jìn)制小數(shù)點(diǎn),直到階碼為0。如果階碼為正數(shù),則將小數(shù)點(diǎn)右移,如果階碼為負(fù)數(shù),則將二進(jìn)制小數(shù)點(diǎn)左移,并在需要的位置前填充導(dǎo)數(shù)0。

新建IEEE表示

實(shí)數(shù)編碼

一旦符號位 階碼和有效數(shù)字字段完成格式化和編碼后,生成一個(gè)完整的二進(jìn)制IEEE段實(shí)數(shù)就很容易了。首先設(shè)置符號位,然后是階碼字段,最后是有效數(shù)字部分。例如:下面表示的是二進(jìn)制1.101x20

  • 符號位:0
  • 階碼:01111111
  • 小數(shù)部分:10100000000000000000000

偏移碼(01111111)是十進(jìn)制數(shù)127的二進(jìn)制形式。所有規(guī)格化有效數(shù)字在二進(jìn)制小數(shù)點(diǎn)的左邊都有個(gè)1,因此,不需要對這一位進(jìn)行顯示編碼。

? 單精度數(shù)位編碼示例

二進(jìn)制數(shù)值偏移階碼符號 階碼 小數(shù)部分
-1.111271 01111111 11000000000000000000000
1101.1011300 10000010 10110100000000000000000

IEEE規(guī)范包含了多鐘實(shí)數(shù)和非數(shù)字編碼

  • 正零和負(fù)零
  • 非規(guī)格化有限數(shù)
  • 規(guī)格化有限數(shù)
  • 正無窮和負(fù)無窮
  • 非數(shù)字
  • 不定數(shù)

規(guī)格化和非規(guī)格化: 規(guī)格化有限數(shù)是指所有非零有限值,這些數(shù)能被編碼為零到無窮之間的規(guī)格化實(shí)數(shù)。盡管看上去全部有限非零浮點(diǎn)數(shù)都應(yīng)被規(guī)格化,但若數(shù)值接近于零,則無法規(guī)格化,當(dāng)階碼范圍造成的限制使得FPU不能將二進(jìn)制小數(shù)點(diǎn)移動(dòng)到規(guī)格化位置時(shí),就會(huì)發(fā)生這種情況。假設(shè)FPU計(jì)算結(jié)果為1.0101111x2-129,其階碼太小,無法用單精度數(shù)形式存放。此時(shí)產(chǎn)生一個(gè)下溢異常,數(shù)值則每次將二進(jìn)制小數(shù)點(diǎn)左移一位逐步進(jìn)行非規(guī)格化,直到階碼達(dá)到有效范圍

正無窮和負(fù)無窮:正無窮表示最大正實(shí)數(shù),負(fù)無窮表示最大負(fù)實(shí)數(shù)。無窮可以和其他數(shù)值比較。負(fù)無窮小于正無窮,負(fù)無窮小于任意有限實(shí)數(shù)。任一無窮都可以表示浮點(diǎn)溢出條件。運(yùn)算結(jié)果不能格式化的原因是,結(jié)果的階碼太大而無法用有效階碼的位數(shù)來表示。

NaN:NaN是不表示任何有效實(shí)數(shù)的位模式

特定編碼:在浮點(diǎn)運(yùn)算中,常常會(huì)出現(xiàn)一些特定的數(shù)值編碼

單精度數(shù)轉(zhuǎn)換為十進(jìn)制

IEEE單精度數(shù)轉(zhuǎn)換為十進(jìn)制時(shí),建議步驟如下:

  • 若MSB為1,該數(shù)為負(fù),否則該數(shù)為正
  • 其后8位為階碼。從中減去127,生成無偏差階碼,將無偏差階碼轉(zhuǎn)換為十進(jìn)制
  • 其后23位表示有效數(shù)字。添加1. 后面緊跟有效數(shù)字位,尾隨零可以忽略。用形成的有效數(shù)字,第一步得到的符號和第二步算出來的階碼,就構(gòu)成了一個(gè)二進(jìn)制浮點(diǎn)數(shù)
  • 對第三步生成的二進(jìn)制數(shù)進(jìn)行非格式化(按照階碼的值移動(dòng)二進(jìn)制小數(shù)點(diǎn),如果階碼為正,則右移,如果階碼為負(fù),則左移)
  • 利用權(quán)位計(jì)數(shù)法,從左到右,將二進(jìn)制浮點(diǎn)數(shù)轉(zhuǎn)換為2的冪之和,形成十進(jìn)制數(shù)
  • 示例IEEE(0 10000010 01011000000000000000000)轉(zhuǎn)換為十進(jìn)制:

  • 該數(shù)為正數(shù)
  • 無偏差階碼的二進(jìn)制值為11 十進(jìn)制為3
  • 將符號 階碼和有效數(shù)字組合起來即得該二進(jìn)制數(shù)為1.01011x23
  • 非規(guī)格化二進(jìn)制數(shù)為1010.11
  • 則該數(shù)的十進(jìn)制值為10.75
  • 浮點(diǎn)單元

    Inter8086處理器設(shè)計(jì)使之只能處理整數(shù)運(yùn)算。這對于使用浮點(diǎn)運(yùn)算的圖形和計(jì)算密集型軟件來說就變成了麻煩。盡管也可以純粹地通過軟件來模擬浮點(diǎn)運(yùn)算,但這樣會(huì)帶來嚴(yán)重的性能損失

    FPU寄存器棧

    FPU不使用通用寄存器,反之,它有自己的一組寄存器,稱為寄存器棧。數(shù)值從內(nèi)存加載到寄存器棧,然后執(zhí)行計(jì)算,再將堆棧數(shù)值保存到內(nèi)存。FPU指令用后綴形式計(jì)算算術(shù)表達(dá)式,這和惠普計(jì)算器的方法大致相同。比如,現(xiàn)有一個(gè)中綴表達(dá)式:(5*6)+4,其后綴表達(dá)式為:5 6 *4 +

    中綴表達(dá)式(A+B)*C要用括號來覆蓋默認(rèn)的優(yōu)先規(guī)則,與之等效的后綴表達(dá)式則不需要括號:A B + C *

    ? 中綴轉(zhuǎn)為后綴的例子

    中綴后綴中綴后綴
    A+BAB+(A+B)*(C+D)AB+CD+*
    (A-B)/DAB-D/((A+B)/C)*(E-F)AB+C/EF-*

    表達(dá)式堆棧:在計(jì)算后綴表達(dá)式的過程中,用堆棧來保存中間結(jié)果

    FPU寄存器

    FPU有8個(gè)獨(dú)立的 可尋址的80位數(shù)據(jù)寄存器R0-R7,這些寄存器合稱為寄存器棧。FPU狀態(tài)字中名為TOP的一個(gè)3位字段給出了當(dāng)前處于棧頂?shù)募拇嫫骶幪枴@?當(dāng)TOP=011時(shí) 表示棧頂為R3。在編寫浮點(diǎn)指令時(shí),這個(gè)位置也稱為ST(0)。最后一個(gè)寄存器為ST(7)

    如同想的一樣,入棧操作將top-1,并把操作數(shù)復(fù)制到標(biāo)識為ST(0)的寄存器中,如果在入棧之前,TOP等于0,那么TOP就回繞到寄存器R7。出棧操作把ST(0)的數(shù)據(jù)復(fù)制到操作數(shù),再將TOP+1。如果在出棧之前TOP=7,則TOP就回繞到寄存器R0。如果加載到堆棧的數(shù)值覆蓋了寄存器棧內(nèi)的原有數(shù)據(jù),就會(huì)產(chǎn)生一個(gè)浮點(diǎn)異常

    盡管理解FPU如何利用一組有限數(shù)量的寄存器實(shí)現(xiàn)堆棧很有意思,但這里只需要關(guān)注ST(n),其中ST(0)總是表示棧頂。從這里開始,引用棧寄存器時(shí)將使用ST(0) ST(1),以此類推。指令操作數(shù)不能直接引用寄存器編號

    寄存器中浮點(diǎn)數(shù)使用的是IEEE10字節(jié)擴(kuò)展實(shí)數(shù)格式,也被稱為臨時(shí)實(shí)數(shù)。當(dāng)FPU把算術(shù)運(yùn)算結(jié)果存入內(nèi)存時(shí),它會(huì)把結(jié)果轉(zhuǎn)換成如下格式之一:整數(shù) 長整數(shù) 單精度 雙精度 或者壓縮二進(jìn)制編碼的十進(jìn)制數(shù)

    專用寄存器

    FPU有6個(gè)專用寄存器

    • 操作碼寄存器:保存最后執(zhí)行的非控制指令的操作碼
    • 控制寄存器:執(zhí)行運(yùn)算時(shí),控制精度以及FPU使用的舍入方法,還可以用這個(gè)寄存器來屏蔽單個(gè)浮點(diǎn)異常
    • 狀態(tài)寄存器:包含棧頂指針 條件碼和異常警告
    • 標(biāo)識寄存器:指明FPU數(shù)據(jù)寄存器棧內(nèi)每個(gè)寄存器的內(nèi)容。其中每個(gè)寄存器都用兩位來表示該寄存器包含的是一個(gè)有效數(shù) 零 特殊數(shù)值還是為空
    • 最后指令指針寄存器:保存指向最后執(zhí)行的非控制指令的指針
    • 最后數(shù)據(jù)(操作數(shù))指針寄存器:保存指向數(shù)據(jù)操作數(shù)的指針,如果存在那么該數(shù)被最后執(zhí)行的指令所使用

    舍入

    FPU嘗試從浮點(diǎn)運(yùn)算中產(chǎn)生非常精確的運(yùn)算結(jié)果,但是在很多情況下這是不可能的,因?yàn)槟繕?biāo)操作數(shù)可能無法精確表示計(jì)算結(jié)果。FPU可以在四種舍入方法中進(jìn)行選擇

  • 舍入到最接近的偶數(shù)
  • 向負(fù)無窮舍入
  • 向正無窮舍入
  • 向0舍入
  • FPU控制字

    FPU控制字用兩位指明使用的舍入方法,這兩位被稱為RC字段。字段數(shù)值如下:

    • 00:舍入到最接近的偶數(shù)(默認(rèn))
    • 01:向負(fù)無窮舍入
    • 10:向正無窮舍入
    • 11:向0舍入

    浮點(diǎn)數(shù)異常

    每個(gè)程序都可能出錯(cuò),而FPU就需要處理這些結(jié)果。因而,它要識別并檢測6種類型的異常條件:無效操作 除零 非規(guī)格化操作數(shù) 數(shù)字上溢 數(shù)字下溢以及模糊精度。前三個(gè)在全部運(yùn)算操作發(fā)生前進(jìn)行檢測,后三個(gè)在操作發(fā)生后進(jìn)行檢測。

    每種異常都有對應(yīng)的標(biāo)志位和屏蔽位。當(dāng)檢測到浮點(diǎn)異常時(shí),處理器將與之匹配的標(biāo)志位置1。每個(gè)被處理器標(biāo)志的異常都有兩種可能的操作:

    • 如果相應(yīng)的屏蔽位置1 那么處理器自動(dòng)處理異常并繼續(xù)執(zhí)行程序
    • 如果相應(yīng)的屏蔽位清0,那么處理器將調(diào)用軟件異常處理程序

    大多數(shù)程序普遍都可以接受處理器的屏蔽響應(yīng)。如果應(yīng)用程序需要特殊響應(yīng),那么可以使用自定義異常處理程序,一條指令能觸發(fā)多個(gè)異常,因此處理器要持續(xù)保存自上一次異常清零后所發(fā)生的全部異常。完成一系列計(jì)算后,可以檢測是否發(fā)生了異常。

    浮點(diǎn)數(shù)指令集

    FPU指令集有些復(fù)雜,因此本節(jié)嘗試對齊功能進(jìn)行概述,并用具體例子給出編譯器通常會(huì)生成的代碼。此外,本節(jié)還將看到如何通過改變舍入模式來控制FPU。指令集包括如下基本指令類型:

    • 數(shù)據(jù)傳送
    • 基本算術(shù)運(yùn)算
    • 比較
    • 超越函數(shù)
    • 常數(shù)加載
    • x87FPU控制
    • x87FPU和SIMD狀態(tài)管理

    浮點(diǎn)指令名用字母F開頭,以區(qū)別CPU指令,指令助記符的第二個(gè)字母(通常為B或I)指明如何解釋內(nèi)存操作數(shù):B表示BCD操作數(shù),I表示二進(jìn)制整數(shù)操作數(shù)。如果這兩個(gè)字母都沒有使用,則內(nèi)存操作數(shù)被認(rèn)為是實(shí)數(shù)。比如,FBLD操作對象為BCD數(shù)值,FILD操作對象為整數(shù),而FLD操作對象為實(shí)數(shù)

    操作數(shù):浮點(diǎn)指令可以包含零操作數(shù) 單操作數(shù)和雙操作數(shù)。如果是雙操作數(shù),那么其中一個(gè)必然為浮點(diǎn)寄存器。指令中沒有立即操作數(shù),但是某些預(yù)定義常數(shù)可以加載到堆棧。通用寄存器EAX EBX…不能作為操作數(shù)。

    整數(shù)操作數(shù)從內(nèi)存加載到FPU,并自動(dòng)轉(zhuǎn)換為浮點(diǎn)格式。同樣,將浮點(diǎn)數(shù)保存到整數(shù)內(nèi)存操作數(shù)時(shí),該數(shù)值也會(huì)被自動(dòng)截?cái)嗷蛏崛霝檎麛?shù)。

    1.初始化(FINIT)

    FINIT指令對FPU進(jìn)行初始化。將FPU控制字設(shè)置為037Fh,即屏蔽了所有浮點(diǎn)異常,舍入模式設(shè)置為最近偶數(shù),計(jì)算精度設(shè)置為64位。建議在程序開始時(shí)調(diào)用FINIT,這樣就可以了解處理器的其實(shí)狀態(tài)

    2.浮點(diǎn)數(shù)據(jù)類型

    MASM支持的浮點(diǎn)類型有:

    • QWORD 64位整數(shù)
    • TBYTE 80位整數(shù)
    • REAL4 32位IEEE短實(shí)數(shù)
    • REAL8 64位IEEE長實(shí)數(shù)
    • REAL10 80位IEEE擴(kuò)展實(shí)數(shù)

    3.加載浮點(diǎn)數(shù)值 FLD

    FLD指令將浮點(diǎn)操作數(shù)復(fù)制到FPU堆棧棧頂(ST(0))。操作數(shù)可以是32位 64位 80位的內(nèi)存操作數(shù)或另一個(gè)FPU寄存器。FLD支持的內(nèi)存操作數(shù)類型與MOV指令一樣

    FILD

    FILD指令將16位 32位或者64位有符號整數(shù)源操作數(shù)轉(zhuǎn)換為雙精度浮點(diǎn)數(shù),并加載到ST(0)。源操作數(shù)符號保留。FILD支持的內(nèi)存操作數(shù)類型和MOV一致

    加載常數(shù)

    下面的指令將特定常數(shù)加載到堆棧,這些指令沒有操作數(shù)

    • FLD1指令將1.0壓入寄存器堆棧
    • FLDL2T指令將log210壓入寄存器堆棧
    • FLDL2E指令將log2e壓入寄存器堆棧
    • FLDPI指令將π壓入寄存器堆棧
    • FLDLG2指令將log102壓入寄存器堆棧
    • FLDLN2指令將loge2壓入寄存器堆棧
    • FLDZ(加載零)指令將0.0壓入FPU堆棧

    保存浮點(diǎn)數(shù)值(FST FSTP FIST)

    FST指令將浮點(diǎn)操作數(shù)從FPU棧頂復(fù)制到內(nèi)存。FST支持的內(nèi)存操作數(shù)類型和FLD一致。操作數(shù)可以為32位 64位 80位內(nèi)存操作數(shù)或另外一個(gè)FPU寄存器

    FSTP(保存浮點(diǎn)值并將其出棧)指令將ST(0)的值復(fù)制到內(nèi)存并將ST(0)彈出堆棧

    FIST(保存整數(shù))指令將ST(0)的值轉(zhuǎn)換為有符號整數(shù),并把結(jié)果保存到目標(biāo)操作數(shù)。保存的值可以為字或者雙字。FIST支持的內(nèi)存操作數(shù)類型與FST一致

    算術(shù)運(yùn)算指令

    下表列出了基本算術(shù)運(yùn)算操作。所有算術(shù)運(yùn)算指令支持的內(nèi)存操作數(shù)類型與FLD(加載)和FST(保存)一致,因此操作數(shù)可以是間接操作數(shù) 變址操作數(shù)和基址變址操作數(shù)等等

    指令作用
    FCHS修改符號
    FADD源操作數(shù)與目的操作數(shù)相加
    FSUB從目的操作數(shù)中減去源操作數(shù)
    FSUBR從源操作數(shù)中減去目的操作數(shù)
    FMUL源操作數(shù)和目的操作數(shù)相乘
    FDIV目的操作數(shù)除以源操作數(shù)
    FDIVR源操作數(shù)除以目的操作數(shù)

    FCHS和FABS

    FCHS(修改符號)指令將ST(0)中的浮點(diǎn)值的符號取反。FABS(絕對值)指令清除ST(0)中數(shù)值的符號,以得到它的絕對值,這兩條指令都沒有操作數(shù)

    FADD FADDP FIADD

    FADD(加法),如果FADD沒有操作數(shù),則ST(0)與ST(1)相加,結(jié)果暫存在ST(1)。然后ST(0)彈出堆棧,把加法結(jié)果保留在棧頂。如果是寄存器操作數(shù),從同樣的棧開始,將ST(0)加到ST(1)。如果是內(nèi)存操作數(shù),FADD將操作數(shù)與ST(0)相加

    FADDP(相加并出棧)指令先執(zhí)行加法操作,再將ST(0)彈出堆棧

    FIADD(整數(shù)加法)指令先將源操作數(shù)轉(zhuǎn)換為擴(kuò)展雙精度浮點(diǎn)數(shù),再與ST(0)相加

    FSUB FSUBP FISUB

    FUSB指令從目的操作數(shù)中減去源操作數(shù),并把結(jié)果保存到目的操作數(shù)。目的操作數(shù)總是一個(gè)FPU寄存器,源操作數(shù)可以是FPU寄存器或內(nèi)存操作數(shù)。該指令操作數(shù)類型和FADD指令一致。

    FUSB的操作與FADD相似,只不過它進(jìn)行的是減法而不是加法。比如,無參數(shù)FUSB實(shí)現(xiàn)ST(1)-ST(0),結(jié)果暫存與ST(1)。然后ST(0)彈出堆棧,將減法結(jié)果留在棧頂。若FSUB使用內(nèi)存操作數(shù),則從ST(0)中減去內(nèi)存操作數(shù),且不再彈出堆棧

    FSUBP(相減并出棧)指令先執(zhí)行減法,再將ST(0)彈出堆棧

    FISUB(整數(shù)減法)指令先把源操作數(shù)轉(zhuǎn)為擴(kuò)展雙精度浮點(diǎn)數(shù),再從ST(0)中減去該操作數(shù)

    FMUL FMULP FIMUL

    FMUL指令將源操作數(shù)與目的操作數(shù)相乘,乘積保存在目的操作數(shù)中。目的操作數(shù)總是一個(gè)FPU寄存器,源操作數(shù)可以為寄存器或者內(nèi)存操作數(shù)。除了執(zhí)行的是乘法不是加法外,FMUL的操作與FADD相同。比如,無參數(shù)FMUL將ST(0)與ST(1)相乘,乘積暫存于ST(1),然后將ST(0)彈出堆棧,將乘積留在棧頂。

    FMULP(相乘并出棧)指令先執(zhí)行乘法,再將ST(0)彈出堆棧

    FIMUL與FIADD相同,只是它執(zhí)行的是乘法不是加法

    FDIV FDIVP FIDIV

    FDIV指令執(zhí)行目的操作數(shù)除以源操作數(shù),被除數(shù)保存在目的操作數(shù)中。目的操作數(shù)總是一個(gè)寄存器,源操作數(shù)可以為寄存器或者內(nèi)存操作數(shù)。其語法與FADD和FSUB相同。

    除了執(zhí)行的是除法不是加法外,FDIV的操作和FADD相同。比如,無參數(shù)FDIV執(zhí)行ST(1)除以ST(0)。然后ST(0)彈出堆棧,將被除數(shù)留在棧頂。使用內(nèi)存操作數(shù)的FDIV將ST(0)除以內(nèi)存操作數(shù)。

    若操作數(shù)為零 則產(chǎn)生除零異常。若源操作數(shù)為正 負(fù)無窮 零 或者NaN,則使用一些特殊情況

    FIDIV指令先將整數(shù)源操作數(shù)轉(zhuǎn)換為擴(kuò)展雙精度浮點(diǎn)數(shù),再執(zhí)行與ST(0)的除法

    比較浮點(diǎn)數(shù)值

    浮點(diǎn)數(shù)不能使用CMP進(jìn)行比較,因?yàn)镃MP是通過整數(shù)減法來執(zhí)行比較的。取而代之,必須使用FCOM指令,執(zhí)行FCOM。執(zhí)行FCOM指令后,還需要采取特殊步驟,然后再使用JCC跳轉(zhuǎn)指令。由于所有的浮點(diǎn)數(shù)都為隱含的有符號數(shù),因此FCOM執(zhí)行的是有符號的比較。

    FCOM FCOMP FCOMPP

    FCOM(比較浮點(diǎn)數(shù))指令將源操作數(shù)與ST(0)進(jìn)行比較。源操作數(shù)可以為內(nèi)存操作數(shù)或者FPU寄存器

    FCOMP指令的操作數(shù)類型和執(zhí)行的操作與FCOM指令相同,但是它要將ST(0)彈出堆棧

    FCOMPP指令與FCOMP相同,但是它有兩次出棧操作

    條件碼

    FPU條件碼標(biāo)識有三個(gè):C3 C2和C0,用以說明浮點(diǎn)數(shù)的比較結(jié)果。C3 C2和C0的功能分別與零標(biāo)志位(ZF) 奇偶標(biāo)志位(PF)和進(jìn)位標(biāo)志位(CF)相同。

    在比較了兩個(gè)數(shù)值并設(shè)置了FPU條件碼之后,遇到的主要挑戰(zhàn)就是怎樣根據(jù)條件分支到相應(yīng)標(biāo)號。這包括兩個(gè)步驟

    • 用FNSTSW指令把FPU狀態(tài)字送入AX
    • 用SAHF指令把AH復(fù)制到EFLAGS寄存器

    條件碼送入EFLAGS之后,就可以根據(jù)ZF CF和PF進(jìn)行條件跳轉(zhuǎn)

    P6處理器的改進(jìn)

    浮點(diǎn)數(shù)比較的運(yùn)行時(shí)開銷大于整數(shù)比較。考慮到這一點(diǎn),InterP6系列引入了FCOMI指令。該指令比較浮點(diǎn)數(shù)值,并直接設(shè)置ZF PF CF

    讀寫浮點(diǎn)數(shù)值

    • ReadFloat:從鍵盤讀取一個(gè)浮點(diǎn)數(shù),并將其壓入浮點(diǎn)堆棧
    • WriteFloat:將ST(0)中的浮點(diǎn)數(shù)以階碼形式寫到控制臺窗口

    異常同步

    整數(shù)(CPU)和FPU是相互獨(dú)立的單元,因此,在執(zhí)行整數(shù)和系統(tǒng)指令的同時(shí)可以執(zhí)行浮點(diǎn)指令。這個(gè)功能被稱為并行性,當(dāng)發(fā)生未屏蔽的浮點(diǎn)異常時(shí),它可能是一個(gè)潛在的問題。反之,已屏蔽異常則不成問題,因?yàn)镕PU總是可以完成當(dāng)前操作并保存結(jié)果。

    發(fā)生未屏蔽異常時(shí),中斷當(dāng)前的浮點(diǎn)指令,FPU發(fā)異常事件信號。當(dāng)下一條浮點(diǎn)指令或者FWAIT指令將要被執(zhí)行時(shí),FPU檢查待處理的異常。如果發(fā)現(xiàn)有這樣的異常,FPU就調(diào)用浮點(diǎn)異常處理程序

    如果引發(fā)異常的浮點(diǎn)指令后面跟的是整數(shù)或系統(tǒng)指令,則指令不會(huì)檢查待處理異常——它們會(huì)立即執(zhí)行

    總結(jié)

    以上是生活随笔為你收集整理的汇编之浮点数处理(CrackMe003前置知识)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。