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

C语言程序转汇编代码的更多相关文章

  1. 分析一个C语言程序生成的汇编代码-《Linux内核分析》Week1作业

    署名信息 郭春阳 原创作品转载请注明出处 :<Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 C源码 这 ...

  2. 解析c语言背后的汇编代码

    源码 很简单的c语言代码,作用是交换两个数: #include <stdio.h> void swap(int * a, int * b) { *a = *a + *b - (*b = * ...

  3. 一个简单C程序的汇编代码分析

    几个重要的寄存器 eip - 用于存放当前所执行的指令地址 esp - 栈(顶)指针寄存器 ebp - 基址(栈底)指针寄存器 简单的C程序 int g(int x) { ; } int f(int ...

  4. 从C简单程序的汇编代码入手,以理解计算机工作原理。

    贺邦  原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000#/info 知识准备 ...

  5. 如何在Visual Studio里面查看程序的汇编代码?

    开发工具:Visual Studio 2015 1,在源代码中设置至少一个断点,目的让我们进入调试模式. 2,启动调试,当程序进入调试模式,停留在我们设定的断点处时候,使用快捷键"ALT+8 ...

  6. 如何在Delphi里面查看程序的汇编代码?

    开发工具:Delphi 10 Update2 1,在源代码中设置至少一个断点,目的让我们进入调试模式. 2,启动调试,当程序进入调试模式,停留在我们设定的断点处时候,使用快捷键"CTRL+A ...

  7. 通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的

    秦鼎涛  <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验一 通过汇编一个简单的C程序,分析汇编代码 ...

  8. Ubuntu16.04 中 Vscode 如何断点调试C语言程序

    个人博客链接:Ubuntu16.04 中 Vscode 如何断点调试C语言程序 问题:环境是 Ubuntu16.04,如何使用 Vscode 断点调试C语言程序. 写代码没有调试环境是不能忍受的,所以 ...

  9. 《Linux内核分析》week1作业-分析一个简单c语言的汇编代码

    1.C语言源码 #include <stdio.h> int g(int x){ ; } int f(int x){ return g(x); } int main(){ )+; } 2. ...

随机推荐

  1. AVR单片机教程——串口接收

    本文隶属于AVR单片机教程系列.   上一讲中,我们实现了单片机开发板向电脑传输数据.在这一讲中,我们将通过电脑向单片机发送指令,让单片机根据指令控制LED.这一次,两端的TX与RX需要交叉连接,单片 ...

  2. Postman post csrf_token

    1.填入代码 var csrf_token = postman.getResponseCookie("csrftoken").value postman.clearGlobalVa ...

  3. Go Web 编程之 数据库

    概述 数据库用来存储数据.只要不是玩具项目,每个项目都需要用到数据库.现在用的最多的还是 MySQL,PostgreSQL的使用也在快速增长中. 在 Web 开发中,数据库也是必须的.本文将介绍如何在 ...

  4. web api 的 安全 认证问题 , 对外开放 的 时候 需要考虑到安全的问题

    关于 OWIN OAuth , web api的认证,全局验证, 安全方面的验证 有必要 去 自己捣鼓一下.

  5. springIOC源码接口分析(十一):ConfigurableApplicationContext

    一 实现接口 关系图: ConfigurableApplicationContext接口实现了三个接口,ApplicationContext, Lifecycle, Closeable, Applic ...

  6. springIOC源码接口分析(七):ApplicationEventPublisher

    一 定义方法 此接口主要是封装事件发布功能的接口,定义了两个方法: /** * 通知应用所有已注册且匹配的监听器此ApplicationEvent */ default void publishEve ...

  7. hadoop-2.10.0安装hive-2.3.6

    公司建立数仓,hive是必不可少的,hive是建立在hadoop基础上的数据库,前面已经搭建起了hadoop高可用,要学习hive,先从搭建开始,下面梳理一下hive搭建过程 1.下载hive安装包 ...

  8. K8S部署遇到的问题处理汇总

    第一个: node节点注册提示:failed to get config map: Unauthorized 代码如下: [root@node1 ~]# kubeadm join --token ll ...

  9. 树莓派4b点亮led灯基本步骤

    方法/步骤1: 首先要了解树莓派上的针脚,下面以树莓派4b为例子 把LED的正极插在GPIO脚上,把负极插在GND上 这里的例子是:正极插在GPIO21 方法/步骤2: 创建脚本 在配置好的树莓派系统 ...

  10. provider networks和self-service networks

    Provider Network 服务布局 Self-Service Network 网络布局: 网络布局 Provider Networks概述  Provider networks - Conne ...