C语言程序转NASM汇编代码

最近在学着写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])

参考链接

  1. https://stackoverflow.com/questions/20737947/how-to-generate-a-nasm-compilable-assembly-code-from-c-source-code-on-linux
  2. https://stackoverflow.com/questions/1647359/is-there-a-way-to-get-gcc-to-output-raw-binary
posted @ 2020-02-27 21:40  l_____py  阅读(...)  评论(...编辑  收藏