最近在學着寫bootloader,由於匯編太繁雜,希望可以使用C語言完成一部分,然后轉成NASM匯編代碼,經過摸索,最終找到了一個解決方案,記錄於此,留作參考。
核心步驟
-
使用gcc編譯得到.o文件
這一步需要加上一些參數對編譯行為進行控制。具體自行參考gcc文檔。
我最終使用的命令參數為
shell gcc -fno-pic -fno-asynchronous-unwind-tables -m32 -O2 -s -c -o $@ $<
具體含義我也沒有深入了解,-m32
是生成32位代碼,-O2
是一種優化級別,-fno-pic
似乎是必要,要不然每個文件最終都會生成一個額外的函數。 -
使用objconv程序將.o文件轉換成匯編代碼
objconv -fnasm $<
objconv可以將.o文件轉成多種形式的匯編,具體自行查閱,上面的參數是要轉成NASM代碼。
-
問題
還有一個問題是,這樣直接轉換成的匯編代碼包含多個段,以及各種對齊指令,以及enbdrXX
指令,需要自己根據需要進行刪減。
我所做的是只保留.text段,並刪減對齊指令、enbdrXX
指令。
我的需求及實現
最終我需要的是將使用C語言完成的函數轉換成匯編形式的函數,並去掉編譯器相關、對齊相關的一些代碼。我的Makefile如下。
all : $(subst .c,.func,$(wildcard *.c))
%.func : %.asm
./extractFunc.py $<
%.asm : %.o
./objconv -fnasm $<
%.o : %.c
gcc -fno-pic -fno-asynchronous-unwind-tables -m32 -O2 -s -c -o $@ $<
clean :
rm -rf *.asm *.o *.func
其功能是將當前目錄中的所有C語言文件轉換成NASM匯編語言文件。
C函數文件示例:
//filename : stripe.c
#define DISPLAY_MEMORY_BASE 0xa0000
#define WIDTH 320
#define HEIGHT 200
void stripe()
{
for (int i = DISPLAY_MEMORY_BASE; i <= DISPLAY_MEMORY_BASE+WIDTH*HEIGHT/2; i++)
{
*((int *)i) = (0b11111100 & i);
}
}
使用make命令得到的結果如下:
; filename : stripe.func
stripe: ; Function begin
mov eax, 655360 ; 0004 _ B8, 000A0000
; Filling space: 7H
; Filler type: lea with same source and destination
; db 8DH, 0B4H, 26H, 00H, 00H, 00H, 00H
?_001: mov edx, eax ; 0010 _ 89. C2
add eax, 1 ; 0012 _ 83. C0, 01
and edx, 0FCH ; 0015 _ 81. E2, 000000FC
mov dword [eax-1H], edx ; 001B _ 89. 50, FF
cmp eax, 687361 ; 001E _ 3D, 000A7D01
jnz ?_001 ; 0023 _ 75, EB
ret ; 0025 _ C3
; stripe End of function
gcc和objconv已經在前面提到過了,那個python腳本的作用刪掉一些我所不需要的代碼,只保留.text
部分,並刪除其中的對齊指令和enbdrXX
指令。內容如下:
#!/usr/bin/python3
#filename : extractFunc.py
import os
import sys
def extractFunc(filename):
fin = open(filename)
lines = fin.readlines()
start = 0
end = 0
lineNum = -1
for line in lines:
lineNum += 1
if line.startswith(f'SECTION .text'):
start = lineNum + 1
continue
if line.startswith(f'SECTION .data'):
end = lineNum
break
funcLines = lines[start:end]
cleanFuncLines = []
for line in funcLines:
if line.startswith(' endbr32') or line.startswith('ALIGN'):
continue
cleanFuncLines.append(line)
fout = open(f'{filename[:-4]}.func', 'w')
fout.writelines(cleanFuncLines)
print(filename)
if __name__ == '__main__':
extractFunc(sys.argv[1])