天天看點

第63部分- Linux x86 64位彙編 FPU之概要 第63部分- Linux x86 64位彙編 FPU之概要Nasm文法gas文法

第63部分- Linux x86 64位彙編 FPU之概要

X87浮點單元FPU,提供高性能浮點處理。從80486就開始支援了。

Intel x87 FPU專門用于執行标量浮點計算,對單精度浮點(32位)、雙精度浮點(64位)以及擴充雙精度浮點(80位)進行計算,并順從IEEE754标準。

FPU的資料寄存器的個數都一樣,隻有8個。對x87 FPU的資料寄存器的通路方式與一般的寄存器有所不同,是棧式通路。通過FLD指令把外部資料搬到x87 FPU的資料寄存器中時,那麼x87 FPU會根據所搬資料的長度(32位、64位、80位)将輸入資料分别對待為單精度浮點、雙精度浮點和擴充雙精度浮點方式,然後統一轉為雙精度擴充模式放到資料棧頂。是以x87 FPU的資料寄存器長度為80位,并且後續的浮點計算都是基于擴充雙精度進行的。

在棧頂的資料寄存器索引為0,那麼它下面一個就是1, 然後是2, 以此類推,到棧底則為7。

資料輸出到存儲器時使用FST或FSTP指令,前者僅僅是根據目标存儲器的長度(32位、64位、80位)将擴充雙精度類型分别轉為單精度、雙精度、擴充雙精度類型,然後輸出到指定的存儲器位置中。FSTP指令,除了将資料搬到外部外,還會執行推出堆棧的操作。

FLD和FST以及FSTP還能搬移FPU内部寄存器的資料,FLD的作用是将指定的FPU資料寄存器位置的資料搬移到棧頂寄存器中,而FST則是将棧頂寄存器的資料搬移到指定的FPU資料寄存器的位置。

由于80位(10個位元組)并不是32位(4個位元組)的整數倍,是以資料加載或存儲雙精度擴充浮點往往是用96位(12個位元組)為機關進行,是以“tbyte”所指的就是“twelve bytes”

Intel彙編格式的位元組、字寬指定修飾詞:byte(位元組,8位),word(字,16位),dword(雙字,32位),qword(四字,64位),tbyte(十二位元組,96位),mmword(64位,但隻能用于MMX指令集中),xmmword(128位,用于SSE指令集),ymmword(256位,用于最新的AVX指令集)。

FPU有以環形堆棧組織的八個10位元組寄存器。 堆棧頂部-寄存器ST(0),其他寄存器為ST(1),ST(2)…ST(7)。 在處理浮點資料時,通常會使用它。

資料傳輸指令

FDL-加載浮點。

FST-存儲浮點(在ST(0)寄存器中)。

FSTP-存儲浮點數(在ST(0)寄存器中)并彈出。

FLD類似于PUSH指令

FSTP類似于POP指令

FADD類似于ADD指令

算術指令:

FADD-浮點加法;// ST(0)與 ST(1)相加,結果暫存在 ST(1)。然後 ST(0) 彈出堆棧,把加法結果保留在棧頂。

FIADD-将整數添加到浮點

FSUB-減去浮點

FISUB-從浮點數減去整數

FABS-獲得絕對值

FIMUL-整數和浮點數相乘

FIDIV-裝置整數和浮點

示例

定義printResult.c檔案如下:

#include <stdio.h>

extern int printResult(double result);

int printResult(double result) {
	printf("Circle radius is - %f\n", result);
	return 0;
}
           
      1. Nasm文法

定義實作的彙編檔案printResult.asm如下:

extern printResult
section .data
		radius    dq  1.7
		result    dq  0

		SYS_EXIT  equ 60
		EXIT_CODE equ 0

global _start
section .text
_start:
		fld qword [radius];//儲存到st(0)
		fld qword [radius] ;//儲存到st(1)
		fmul;//将 ST(O) 與 ST(1) 相乘,乘積暫存于ST(1)。然後 ST(0) 彈出堆棧,将乘積則繼續留在棧頂。
		fldpi;//裝入浮點的pi,就是裝入st(1)
		fmul;//将ST(O) 與 ST(1) 相乘,儲存到st(0)
		fstp qword [result];//将結果儲存到[result]

		mov rax, 0;// 表示xmmN寄存器的數量放入rax寄存器
		movq xmm0, [result];//将參數也就是結果放到xmm0.
		call printResult

		mov rax, SYS_EXIT;退出系統調用的号
		mov rdi, EXIT_CODE
	  syscall
           

其中DQ作為彙編語言中的僞操作指令,用來定義操作數占用的位元組數,占有4個字,即8個位元組(64位),可用來存放雙精度浮點數。

浮點參數的傳參有特殊的寄存器:sse提供的xmm0-xmm15(而不是通常的rdi,rsi……)。需要将xmmN寄存器的數量放入rax寄存器(本例中為0),然後将結果放入xmm0寄存器。

編譯如下:

gcc -g -c printResult.c -o c.o

nasm -f elf64 printResult.asm -o printResult.o

ld   -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc printResult.o  c.o -o printResult

gas文法

定義實作的彙編檔案如下:

printResult.s

.extern printResult

.section .data
		radius:    .double  1.7
		result:    .double  0

		.equ SYS_EXIT , 60
		.equ EXIT_CODE,  0

.global _start
.section .text
_start:
		leaq radius,%rbx
		fldl (%rbx)
		fldl (%rbx)
		fmulp

		fldpi
		fmulp
		fstl result

		movq  $0,%rax
		movq result, %xmm0
		call printResult

		movq  $SYS_EXIT,%rax
		movq  $EXIT_CODE,%rdi
           syscall
           

編譯如下:

gcc -g -c printResult.c -o c.o

as -g -o printResult.o  printResult.s

ld   -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc printResult.o  c.o -o printResult

tips:在gdb中可以時候用print $st0來列印寄存器中 值。

繼續閱讀