xv6 makefile详解

news2024/11/15 11:14:29

文章目录

  • makefile语法格式
  • 生成qemu可执行文件
    • 生成kernel可执行文件
      • 生成kernel下的OBJS
      • kernel.ld
      • build OBJS_KCSAN
      • build initcode
    • 生成一个fs.img文件系统
      • mkfs
      • 用户程序的编译
  • 配置工具

makefile语法格式

makefile就是一个深搜的过程,最上面的语句是顶级目标,顶级目标还有依赖

如果依赖不存在,下面我们还要写,

所以就是上面没有的,要在下面实现,再下面都实现了,上面的顶级目标才能实现

生成qemu可执行文件

make qemu

qemu 依赖于kernelfs.img,把内核加载进去,文件系统挂载进去,之后一个操作系统就可以跑起来了

模拟risc-v指令集的CPU,比较关键的就是-kernel $K/kernel和-driver file=fs.img


QEMU = qemu-system-riscv64	# 指定QEMU版本risc-v 的CPU
# --》 指定了使用的操作内核是kernel/kernel,-m 模拟了操作系统使用的内存128M,使用了3个cpu个数,
QEMUOPTS = -machine virt -bios none -kernel $K/kernel -m 128M -smp $(CPUS) -nographic
# 
QEMUOPTS += -global virtio-mmio.force-legacy=false
# 把文件系统挂载上去,最终就是模拟出来的一个计算机
QEMUOPTS += -drive file=fs.img,if=none,format=raw,id=x0
QEMUOPTS += -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0

ifeq ($(LAB),net)
QEMUOPTS += -netdev user,id=net0,hostfwd=udp::$(FWDPORT)-:2000 -object filter-dump,id=net0,netdev=net0,file=packets.pcap
QEMUOPTS += -device e1000,netdev=net0,bus=pcie.0
endif

# qemu依赖于kernel, fs.img  
qemu: $K/kernel fs.img
	$(QEMU) $(QEMUOPTS)------->这里有了操作系统和用户程序还缺少硬件

生成kernel可执行文件

$K/kernel: $(OBJS) $(OBJS_KCSAN) $K/kernel.ld $U/initcode
# 把所有.o文件用kernel.ld配置的链接器进行链接起来,生成一个kernel
	$(LD) $(LDFLAGS) -T $K/kernel.ld -o $K/kernel $(OBJS) $(OBJS_KCSAN)
# 把kernel反汇编成kernel.asm,让我们能够进行debug
	$(OBJDUMP) -S $K/kernel > $K/kernel.asm
# 把asm中的一些数据进行过滤,方便进行查找  
	$(OBJDUMP) -t $K/kernel | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $K/kernel.sym

生成kernel下的OBJS

kernel下的许多程序函数,都需要在 kernel/main.c函数中使用

(1)编译目标定义


# 展开kernel/entry.o
# s\换行符
# 我们可以把OBJS这个变量别名理解为一个string
# 这里是编译内核态的代码,kernel依赖于这些代码
# 所以这下面的要一个一个开始生成
OBJS = \
  $K/entry.o \
  $K/kalloc.o \
  $K/string.o \
  $K/main.o \
  $K/vm.o \
  $K/proc.o \
  $K/swtch.o \
  $K/trampoline.o \
  $K/trap.o \
  $K/syscall.o \
  $K/sysproc.o \
  $K/bio.o \
  $K/fs.o \
  $K/log.o \
  $K/sleeplock.o \
  $K/file.o \
  $K/pipe.o \
  $K/exec.o \
  $K/sysfile.o \
  $K/kernelvec.o \
  $K/plic.o \
  $K/virtio_disk.o

%.o就是一个通配符,所有的.o都依赖于.c文件,这些都是kernel下的程序

$K/%.o: $K/%.c
	$(CC) $(CFLAGS) $(EXTRAFLAG) -c -o $@ $<

.S汇编都是下面这样生成的

riscv64-linux-gnu-gcc -c -o kernel/entry.o kernel/entry.S

.c就是下面这样编译的,规则是不一样的

riscv64-linux-gnu-gcc -Wall -Werror -O -fno-omit-frame-pointer -ggdb -gdwarf-2 -DSOL_PGTBL -DLAB_PGTBL -MD -mcmodel=medany -ffreestanding -fno-common -nostdlib -mno-relax -I. -fno-stack-protector -fno-pie -no-pie -c -o kernel/kalloc.o kernel/kalloc.c

到这里整个 kernelOBJS 都被build


kernel.ld

这是kernel目录底下的链接脚本,指导着我们把kernel的依赖文件链接成一个目标文件

链接器 ld 将按照脚本内的指令将 .o文件生成可执行文件

主要描述的就是处理链接脚本的方式,以及生成可执行文件的内容布局

OUTPUT_ARCH( "riscv" )
ENTRY( _entry )虚拟地址的路口
这下面都是虚拟地址,这个就是kernel的虚拟地址空间
SECTIONS
{
  /*
   * ensure that entry.S / _entry is at 0x80000000,
   * where qemu's -kernel jumps.
   */
  . = 0x80000000;这个就是设置entry入口为0x80000000,“."就是当前位置
  /*
   * 这里text里面存放的就是用户的代码

  */
  .text : {
    *(.text .text.*)把目标文件中的所有.o文件中的text节都拿出来,生成一个全新的text节
    . = ALIGN(0x1000);做一个4KB对齐
    _trampoline = .;保存trampoline代码,记录当前位置
    *(trampsec)	保存trampoline代码
    . = ALIGN(0x1000);
    ASSERT(. - _trampoline == 0x1000, "error: trampoline larger than one page");
    PROVIDE(etext = .);
  }

  .rodata : {
    . = ALIGN(16);
    *(.srodata .srodata.*) /* do not need to distinguish this from .rodata */
    . = ALIGN(16);
    *(.rodata .rodata.*)
  }

  .data : {
    . = ALIGN(16);
    *(.sdata .sdata.*) /* do not need to distinguish this from .data */
    . = ALIGN(16);
    *(.data .data.*)
  }

  .bss : {
    . = ALIGN(16);
    *(.sbss .sbss.*) /* do not need to distinguish this from .bss */
    . = ALIGN(16);
    *(.bss .bss.*)
  }

  PROVIDE(end = .);
}


build OBJS_KCSAN

这些程序都是处理和硬件中断相关的程序

OBJS_KCSAN = \
  $K/start.o \
  $K/console.o \
  $K/printf.o \
  $K/uart.o \
  $K/spinlock.o

$K/%.o: $K/%.c
	$(CC) $(CFLAGS) $(EXTRAFLAG) -c -o $@ $<

build initcode

用户空间初始化程序

kernel/main.c中使用到了这个程序,执行第一个用户程序 "init"程序,这一段可加可不加,kernel编译中只加了这一部分

// a user program that calls exec("/init")
// assembled from ../user/initcode.S
// od -t xC ../user/initcode
uchar initcode[] = {
    0x17, 0x05, 0x00, 0x00, 0x13, 0x05, 0x45, 0x02,
    0x97, 0x05, 0x00, 0x00, 0x93, 0x85, 0x35, 0x02,
    0x93, 0x08, 0x70, 0x00, 0x73, 0x00, 0x00, 0x00,
    0x93, 0x08, 0x20, 0x00, 0x73, 0x00, 0x00, 0x00,
    0xef, 0xf0, 0x9f, 0xff, 0x2f, 0x69, 0x6e, 0x69,
    0x74, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00};


$U/initcode: $U/initcode.S
	$(CC) $(CFLAGS) -march=rv64g -nostdinc -I. -Ikernel -c $U/initcode.S -o $U/initcode.o
	$(LD) $(LDFLAGS) -N -e start -Ttext 0 -o $U/initcode.out $U/initcode.o
	$(OBJCOPY) -S -O binary $U/initcode.out $U/initcode
	$(OBJDUMP) -S $U/initcode.o > $U/initcode.asm

生成一个fs.img文件系统

这个就是生成一个文件系统,相当于一个硬盘的镜像(用来存放用户程序的)

这里的mkfs/mkfs程序,就是将后面的 ( U P R O G S ) , (UPROGS), (UPROGS),(UEXTRA)用户编译好的程序,写入 fs.img这个文件系统中

# 这些都是伪目标,可以直接使用
fs.img: mkfs/mkfs README $(UEXTRA) $(UPROGS)
	mkfs/mkfs fs.img README $(UEXTRA) $(UPROGS)

mkfs/mkfs fs.img README user/_cat user/_echo user/_forktest user/_grep user/_init user/_kill user/_ln user/_ls user/_mkdir user/_rm user/_sh user/_stressfs user/_usertests user/_grind user/_wc user/_zombie user/_pgtbltest

mkfs

mkfs/mkfs: mkfs/mkfs.c $K/fs.h $K/param.h
	gcc $(XCFLAGS) -Werror -Wall -I. -o mkfs/mkfs mkfs/mkfs.c

mkfs/mkfs就是往文件系统中写文件的程序

gcc -DSOL_PGTBL -DLAB_PGTBL -Werror -Wall -I. -o mkfs/mkfs mkfs/mkfs.c

用户程序的编译

UPROGS=\
	$U/_cat\
	$U/_echo\
	$U/_forktest\
	$U/_grep\
	$U/_init\
	$U/_kill\
	$U/_ln\
	$U/_ls\
	$U/_mkdir\
	$U/_rm\
	$U/_sh\
	$U/_stressfs\
	$U/_usertests\
	$U/_grind\
	$U/_wc\
	$U/_zombie\

ULIB = $U/ulib.o $U/usys.o $U/printf.o $U/umalloc.o	#  这个对标的就是C语言中的一些库函数,如printf,malloc之类的
# 这里的_就是一个字符,后面的%就是匹配所有以_开头的文件
# 依赖中的%.o,就是匹配所有.o结尾的文件,同时还要添加一个ULIB,依次去匹配这些东西
_%: %.o $(ULIB)
	$(LD) $(LDFLAGS) -T $U/user.ld -o $@ $^
	$(OBJDUMP) -S $@ > $*.asm
	$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym

ulib中包含的就是一些string和内存操作的一些库函数
printf 包含了和标准输出相关的一些函数
umalloc包含了malloc相关的动态开辟之类的函数
usys里面包含的就是系统调用相关的入口函数

这些将来就可以被OS调用,从文件系统中加载到内存中进行执行

用户态生成这些应用文件

硬盘构建完了上面这些在mkfs中使用到的编译完之后,就能构建fs.img

配置工具

指定工具的版本,如果找不到合适的版本就输出错误信息

TOOLPREFIX := $(shell if riscv64-unknown-elf-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
	then echo 'riscv64-unknown-elf-'; \
	elif riscv64-linux-gnu-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
	then echo 'riscv64-linux-gnu-'; \
	elif riscv64-unknown-linux-gnu-objdump -i 2>&1 | grep 'elf64-big' >/dev/null 2>&1; \
	then echo 'riscv64-unknown-linux-gnu-'; \
	else echo "***" 1>&2; \
	echo "*** Error: Couldn't find a riscv64 version of GCC/binutils." 1>&2; \
	echo "*** To turn off this error, run 'gmake TOOLPREFIX= ...'." 1>&2; \
	echo "***" 1>&2; exit 1; fi)

配置编译器汇编器链接器copy工具dump工具(反汇编)


CC = $(TOOLPREFIX)gcc		#  指定编译器
AS = $(TOOLPREFIX)gas		#  汇编器
LD = $(TOOLPREFIX)ld		#  链接器,前面都加上工具的版本
OBJCOPY = $(TOOLPREFIX)objcopy	# 把一个目标文件的内容拷贝到另一个目标文件中
OBJDUMP = $(TOOLPREFIX)OBJDUMP	# objdump是把二进制文件反汇编成一个.asm文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/97061.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

python-函数、文件、异常、模块

目录 函数 返回值 函数传参 位置参数 关键字传参 缺省参数 不定长参数 匿名函数 文件操作 open 函数 异常 模块 导入模块 函数 返回值 return语句[表达式]退出函数&#xff0c;选择性地向调用方返回一个表达式。不带参数值的return语句返回None #定义函数 def a…

Ubuntu系统装机流程(显卡驱动、cuda、cudnn、搜狗输入法、anaconda、pycharm)

整体流程一、安装Ubuntu18.04系统二、安装显卡驱动三、安装Cuda四、安装Cudnn五、安装搜狗输入法六、安装Anaconda七、安装Pycharm社区版一、安装Ubuntu18.04系统 &#xff08;1&#xff09;实现用软碟通做好一个装有Ubuntu18.04的系统盘。 &#xff08;2&#xff09;打开电脑…

Jenkins自动发布到Docker部署服务器把Jar包打包成镜像并启动容器

《jenkins自动化发布到服务器并自动运行》 第1种方法&#xff1a;使用外部Jar包完成自动化部署&#xff08;简单方便&#xff09;&#xff0c;正式环境更新jar包时&#xff0c;备份一下旧的的jar包即可。 修改jenkins项目配置 Pre Steps 构建前清除旧的jar包&#xff0c;然后…

计算机网络原理第2章 物理层

目录 2.1 物理层的基本概念 2.2.1 数据通信系统的模型 2.2.2 有关信号的几个基本概念 1.通信 2.调制 3.编码 2.2.3 信道的极限容量 1.信道能够通过的频率范围&#xff08;奈氏准则&#xff09; 2. 信噪比&#xff08;香农公式&#xff09; 3.奈氏准则与香农公式的比…

Linux操作系统CentOS7安装mysql5.7.x

一、下载mysql5.7.x安装包 &#x1f308; MySQL官方下载&#xff1a;https://dev.mysql.com/downloads/mysql/5.7.html 注意&#xff0c;需要在Windows上解压之后&#xff0c;会有两个压缩包&#xff0c;将其中一个上传 二、将mysql5.7.x安装包上传到Linux服务器 使用 Xftp 上传…

NeurIPS 2022 Spotlight | SNAKE:首个同时进行隐式重建和三维特征点提取的方法

原文链接&#xff1a;https://www.techbeat.net/article-info?id4361 作者&#xff1a;钟程亮 3D特征点检测在物体识别、场景重建等任务中有着重要作用。然而由于点云数据采样的稀疏性&#xff0c;从中检测出3D特征点是一项很有挑战性的任务。虽然原始点云的获取方式有很多种&…

Kafka基础_1

Kafka系列 注&#xff1a;大家觉得博客好的话&#xff0c;别忘了点赞收藏呀&#xff0c;本人每周都会更新关于人工智能和大数据相关的内容&#xff0c;内容多为原创&#xff0c;Python Java Scala SQL 代码&#xff0c;CV NLP 推荐系统等&#xff0c;Spark Flink Kafka Hbase …

一文讲懂泛型

Java高级Java高级语言特性一. 泛型1. 1 为什么我们需要泛型1. 2 泛型类和泛型接口的定义1. 3 泛型方法1. 4 限定类型变量1. 5 泛型中的约束和局限性1. 6 泛型中的继承规则1. 7 通配符类型1.7.1 问题抛出&#xff0c;为啥需要通配符&#xff1f;1.7.2 &#xff1f; extends X1.7…

RocketMq的基本概念

&#x1f3b6; 文章简介&#xff1a;RocketMq的基本概念 &#x1f4a1; 创作目的&#xff1a;关于RocketMq的基本概念的大致介绍 ☀️ 今日天气&#xff1a;阳光明媚。 &#x1f4dd; 每日一言&#xff1a;冬有冬的来意&#xff0c;雪有雪的秘密。 文章目录&#x1f436; 1、Ro…

MySQL~DQL查询数据

4、DQL查询数据&#xff08;最重点&#xff09; 4.1、DQL &#xff08;Data Query LANGUAGE&#xff1a;数据查询语言&#xff09; 所有的查询操作都用它 Select简单的查询&#xff0c;复杂的查询它都能做~数据库中最核心的语言&#xff0c;最重要的语句使用频率最高 SELEC…

Kafka 集群部署与测试

安装Kafka&#xff08;需要JDK和Zookeeper&#xff09;: 下载Kafka安装包&#xff0c;并解压至node01节点中的/opt/apps目录下。修改配置文件。在server.properties配置文件中指定broker编号、Kafka运行日志存放的路径、指定Zookeeper地址和本地IP。添加环境变量。在/etc/prof…

[ vulhub漏洞复现篇 ] GhostScript 沙箱绕过(任意命令执行)漏洞CVE-2018-19475

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…

【IDEA】# 快速生成logger、通过Maven的profile配置实现环境的快速切换、常用基础设置

1. 快速生成logger 打开 Settings&#xff0c;找到 Editor 目录下的 Live Templates 选中 Java&#xff0c;点击右侧的加号&#xff0c;创建一个新的模板 在创建模板的相关位置&#xff0c;填上对应的值 Abbreviation&#xff1a;触发的关键字&#xff08;此处我使用的是 l…

Postman进阶篇(十二)-在脚本中使用pm对象访问接口响应数据(pm.response.*)

在之前的文章中介绍过postman中的两个脚本——pre-request script或test script&#xff0c;在这两个脚本中都有使用到pm对象。&#xff08;pre-request script详细介绍、Test script详细介绍&#xff09;pm对象是在postman的脚本中非常重要&#xff0c;也是十分常用的方法。本…

SpringCloud学习笔记 - Nacos配置中心搭建 - Nacos Config

Nacos 提供用于存储配置和其他元数据的 key/value 存储&#xff0c;为分布式系统中的外部化配置提供服务器端和客户端支持。使用 Spring Cloud Alibaba Nacos Config&#xff0c;您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外部属性配置。 Spring Cloud Alibaba Nac…

Volo - Rust gRPC 框架入门

一、参考资料 Volo-GitHub Volo-Overview 二、开发环境搭建 1、安装脚手架 # 安装 volo-cli cargo install volo-cli # 验证安装 volo help 2、编写 IDL # 文件 volo_demo.protosyntax "proto3"; package volo.demo;message Item {int64 id 1;string title …

React学习26(react-redux优化 工作使用)

项目结构 优化说明 1&#xff09;容器组件和UI组件混合成一个文件 2&#xff09;无需自己给容器传递store&#xff0c;在index.js入口文件给包裹一个Provider <Provider store {store}><App/> </Provider> 3&#xff09;使用了react-redux后也不用自己在…

Python入门教程:基本运算符

1.运算符 计算机可以进行的运算有很多种&#xff0c;可不只加减乘除这么简单&#xff0c;运算按种类可分为算数运算、比较运算、逻辑运算、赋值运算、成员运算、身份运算、位运算&#xff0c;今天我们暂只学习算数运算、比较运算、逻辑运算、赋值运算、成员运算 2.算数运算 …

数据聚合、数据同步

文章目录数据聚合Bucket聚合语法聚合结果排序限定聚合范围Metric聚合语法RestAPI实现聚合数据同步发送MQ消息接收MQ消息数据聚合 Bucket聚合语法 GET /hotel/_search {"size": 0, // 设置size为0&#xff0c;结果中 不包含文档&#xff0c;只包含聚合结果~"…

Spark-内核(集群管理器、通讯架构、任务调度机制、Shuffle、内存管理)

文章目录Spark内核Spark部署模式的集群管理器YARN模式运行机制Standalone模式运行机制Spark通讯架构通信架构概述通讯架构解析Spark任务调度机制任务调度概述Stage级调度Spark Task级调度调度策略本地化调度失败重试与黑名单机制Spark Shuffle解析ShuffleMapStage与ResultStage…