彙編函數閱讀筆記

memset

原型

void memset(void* p_dst, char ch, int size)

這是memset的函數原型,在C語言中使用這個函數時,需按這個原型傳參。函數

memset的功能是:用sizechar類型的數據填充初始內存地址是p_dst的這片內存空間。oop

代碼

global	memset

memset:
	push	ebp
	mov	ebp, esp

	push	esi
	push	edi
	push	ecx

	mov	edi, [ebp + 8]	; Destination
	mov	edx, [ebp + 12]	; Char to be putted
	mov	ecx, [ebp + 16]	; Counter
.1:
	cmp	ecx, 0		; 判斷計數器
	jz	.2		; 計數器爲零時跳出

	mov	byte [edi], dl		; ┓
	inc	edi			; ┛

	dec	ecx		; 計數器減一
	jmp	.1		; 循環
.2:

	pop	ecx
	pop	edi
	pop	esi
	mov	esp, ebp
	pop	ebp

	ret			; 函數結束,返回

解讀

函數模板

nasm彙編寫函數的模板是:測試

; 函數名
funcName:
	; 被修改的寄存器都要事先存儲到堆棧中,因此,ebp、eax、ebx、ecx都要入棧
	push	ebp
	mov		ebp,	esp
	
	push	eax
	push	ebx
	push	ecx
	
	; 調用funcName時,參數按照從右到左依次入棧
	; ebp + 0 是 eip,ebp + 4 是esp
	mov	eax,	[ebp + 16]	; 第三個參數
	mov	ebx,	[ebp + 12]	; 第二個參數
	mov	ecx,	[ebp + 8]		; 第一個參數
	
	; some code
	; some code
	
	; 在函數末尾經過出棧還原被修改過的寄存器中的值,出棧順序和簽名的入棧順序相同
	pop	ecx
	pop	ebx
	pop	eax
	pop	ebp
	
	; 函數末尾必須用這個指令結尾,出棧esp和eip。
	ret

使用

要在其餘文件中使用這個函數,需在本文件使用global memset將此函數導出。rest

其餘

.1:
	cmp	ecx, 0		; 判斷計數器
	jz	.2		; 計數器爲零時跳出

	mov	byte [edi], dl		; ┓
	inc	edi			; ┛

	dec	ecx		; 計數器減一
	jmp	.1		; 循環

dl是第二個參數char chchar是8個字節,所以只須要使用寄存器dlcode

mov byte [edi], dlch填充到es:edi內存空間。視頻

.1:
	;some code
	;some code
	jmp .1

jmp實現循環指令。能不用loop指令就不用。loop指令必須與ecx配合使用,很是容易出錯。進程

out_byte

; 函數名稱是 out_byte
out_byte:
	; esp 是 eip
	mov	edx, [esp + 4]		; port,第一個參數
	mov	al, [esp + 4 + 4]	; value,第二個參數
	; 把al寫入dx端口
	out	dx, al
	nop	; 一點延遲
	nop
	; 堆棧中的eip出棧
	ret

in_byte

; 函數名稱是 in_byte
in_byte:
	mov	edx, [esp + 4]		; port,第一個參數
	xor	eax, eax	; 設置eax的值是0。異或運算,不相等結果是1,相等結果是0。
	in	al, dx		; 把dx端口的值寫入dl
	nop	; 一點延遲
	nop
	ret

disp_str

代碼

disp_str:
	push	ebp
	mov	ebp, esp

	mov	esi, [ebp + 8]	; pszInfo
	mov	edi, [disp_pos]
	mov	ah, 0Fh
.1:
	lodsb
	test	al, al
	jz	.2
	cmp	al, 0Ah	; 是回車嗎?
	jnz	.3
	push	eax
	mov	eax, edi
	mov	bl, 160
	div	bl
	and	eax, 0FFh
	inc	eax
	mov	bl, 160
	mul	bl
	mov	edi, eax
	pop	eax
	jmp	.1
.3:
	mov	[gs:edi], ax
	add	edi, 2
	jmp	.1

.2:
	mov	[disp_pos], edi

	pop	ebp
	ret

理解這個函數花了不少時間。緣由是沒有及時聯想到讀寫顯存的座標知識。ip

流程

流程是:內存

  1. 從參數pszInfo加載一個字節數據到al
  2. 測試al是否爲空。
    1. 爲空,函數結束。
    2. 非空
      1. 字符不是回車,打印字符,視頻段偏移量自增2個字節,而後跳轉到最外層流程1。
      2. 字符是回車,不打印這個字符,
        1. 計算出視頻偏移量。計算方法是:
          1. 先計算出當前視頻偏移量在第N行,計算公式是:視頻偏移量/160
          2. 要打印的新字符所在行數應該是:N+1
          3. 將新行數轉換成視頻偏移量:(N+1)*160
        2. 跳轉到最外層流程1。

顯存座標

[gs:(80*1+0)*2],把字符寫入第1行第1列。字符串

[gs:(80*2+1)*2],把字符寫入第1行第2列。

指令

lodsb

lodsb,把[ds:si]處的數據讀入alsi自動自增1。

test

test	al, al
jz	.2

al爲空時,跳轉到.2

cmp

cmp	al, 0Ah	; 是回車嗎?
jnz	.3

al的值不是0Ah時,跳轉到.30Ah是回車鍵的ASCII碼。

div

mov	eax, edi
mov	bl, 160
div	bl
and	eax, 0FFh

div是除法。被除數在eax中,除數在bl中,商在al中,餘數在ah中。

and eax, 0FFh獲取al中的值。

disp_color_str

disp_color_str:
	push	ebp
	mov	ebp, esp

	mov	esi, [ebp + 8]	; pszInfo
	mov	edi, [disp_pos]
	mov	ah, [ebp + 12]	; color
.1:
	lodsb
	test	al, al
	jz	.2
	cmp	al, 0Ah	; 是回車嗎?
	jnz	.3
	push	eax
	mov	eax, edi
	mov	bl, 160
	div	bl
	and	eax, 0FFh
	inc	eax
	mov	bl, 160
	mul	bl
	mov	edi, eax
	pop	eax
	jmp	.1
.3:
	mov	[gs:edi], ax
	add	edi, 2
	jmp	.1

.2:
	mov	[disp_pos], edi

	pop	ebp
	ret

只在disp_str的基礎上增長了一句mov ah, [ebp + 12] ; color,設置打印字符串的顏色,其餘部分與disp_str徹底一致。

restart

restart:
	mov	esp, [p_proc_ready]
	lldt	[esp + P_LDT_SEL] 
	lea	eax, [esp + P_STACKTOP]
	mov	dword [tss + TSS3_S_SP0], eax

	pop	gs
	pop	fs
	pop	es
	pop	ds
	popad

	add	esp, 4

	iretd

這是構造好進程後,啓動第一個進程使用的函數。

語法很好懂,難點在業務邏輯。

指令

lldt

lldt [esp + P_LDT_SEL] ,加載LDT。[esp + P_LDT_SEL]是LDT的選擇子。

lea

假設,si = 1000h,ds = 50000h,(51000h)=1234h,那麼

  1. lea ax, [ds:si]執行後,ax的值是1000h
  2. mov ax, [d:si]執行後,ax的值是1234h

lea eax, [esp + P_STACKTOP]執行後,eax的值是一個偏移量,是內存地址,而不是內存esp + P_STACKTOP中的值。

popad

popad依次出棧EDI,ESI,EBP,ESP,EBX,EDX,ECX,EAX

iretd

暫時沒有找到權威資料。

業務邏輯

  1. [p_proc_ready]指向進程表的初始位置。j
  2. 初始位置正好是存儲寄存器的結構regs。
  3. P_LDT_SEL是regs的長度。[esp + P_LDT_SEL] 跳過regs,指向進程表的第二個成員結構,是LDT的選擇子。
  4. 其實[esp + P_LDT_SEL] [esp + P_STACKTOP]指向同一個內存單元。總之,這個時候,指向regs的棧頂。
  5. mov dword [tss + TSS3_S_SP0], eax,讓TSSsp0指向regs的棧頂。
  6. 接下來,執行pop操做時,CPU挑選的是0特權級的ss0sp0,因此,出棧的棧是進程表中的regs。
相關文章
相關標籤/搜索