zig语言代替C语言进行裸机开发的尝试-2023年笔记

news2024/11/15 15:46:30

接触rust的时候,无意中认识了zig,目前版本是zig 0.10.0,还没有正式的1.0版本。

初步使用的感受:
1). 用zig写出的代码更防崩,不会像C那样出现很多内存非法访问的情况
   (比如这些情形:栈保护、整数溢出、下标越界、OOM、DF、Leak。。。)
2). 拥有“类”语法,相同功能的项目开发过程中,所需编写的总代码量肯定会比C少
3). 比Rust/C++容易学,但是比C稍难学一点点
4). 基于LLVM开发的编译器,天生支持交叉编译多种cpu架构的目标代码
5). 可与C、asm进行混合开发,兼容C/C++,完全可以拿来当另一个C编译器用
6). 支持编译期代码
7). 可以源码中集成单元测试代码
8). 自带基于自身脚本的构建系统,不需要makefile之类的
9). 支持 try catch exception处理
10). 编译速度快(网传)
11). MIT许可(相当宽松)
12). 原生支持异步
13). 支持将C代码转换成zig代码

缺点及风险:
1). 小团队开发维护的编程语言,目前网上能看到的只有跟Uber一家有合作。
2). 未成熟、定型,还在变,比如三年前的zig项目,现在已经不能直接编译了。(构建脚本已变)
3). 小众,国内用的人更加少,文档不全,中文的资料更是少得可怜。

安装过程很简单
官网有编译好的,下载解压,添加路径即可。

下载 ⚡Zig Programming Language

只有一个可执行文件:zig
项目创建、构建都是用这个指令。

下面是用zig做aarch64(armv8a)裸机开发的内容,展示了zig的基本用法:
包括基本语法、类的静态成员函数、类实例的成员函数、
与C/asm互调、混合编译、链接、构建脚本、交叉编译、MMIO读写。。。

源码目录结构:

 编译指令:

zig  build         #生成elf格式文件,体积为130Kb上下
zig  build  bin  #生成bin格式文件,40Kb,不调用C的话27Kb左右

在build.zig中将编译模式调整为 "safety off" 后,编译体积甚至比C还要小,bin文件输出不到1kb!

    elf.setBuildMode(std.builtin.Mode.ReleaseSmall);//mode);

 src/main.zig:


const std = @import("std");
const io = std.io;
const os = std.os;

const a_number: i32 = 1234;

export fn main() void {
	const uart = UART.init();
	const out = uart.getWriter();
	out.print("Hello1, {s}!\r\n", .{"world"}) catch return;
	UART.putc(0x63);
	UART.putc('a');
	UART.putc('\n');
	out.print("Hello2, {s}  {}==0x{X}!\r\n", .{"世界", a_number, a_number}) catch return;
	out.print("Hello3, {}\r\n", .{cEng.c_func(3, 8)}) catch return;
	while(true) 
	{
		var c = UART.getc();
		out.print("-->{c}!\r\n", .{c}) catch return;
	}
	out.print("Hello4, {s}!\r\n", .{"world"}) catch return;
}

const UART0DR = @intToPtr(*volatile u8, 0x09000000);
const UART0FR = @intToPtr(*volatile u8, 0x09000018);

pub const UART = struct {

	inited: i32 = 0,

    pub fn init() UART {
        return UART {
            .inited = 1,
        };
    }
	
	pub fn putc(ch:u8) void
	{
		while (  ((UART0FR.*) & (1 << 5)) != 0  ) {}
		UART0DR.* = ch;
	}

	pub fn getc() u8
	{
		while (  ((UART0FR.*) & (1 << 4)) != 0   ) {}
		var ch = UART0DR.*;
		return ch;
	}

	pub fn doWrite(self:UART, bytes: []const u8) WriteError!usize {
		if(self.inited > 0) {}

		var i:usize=0;
		for (bytes) |c| {
			putc(c);
			i += 1;
		}
		
		return i;
	}

    pub const WriteError = os.WriteError;
    pub const Writer = io.Writer(UART, WriteError, doWrite);
	pub fn getWriter(uart: UART) Writer {
        return .{ .context = uart };
	}
};

export fn zig_func(a: i32, b: i32) i32 {
    return a + b;
}

const cEng = @cImport({
    @cDefine("ZIG_WITH_C", "1");
    @cInclude("coWork.h");
});

src/boot.S:

.section ".text.boot"

.global _start
_start:
  mrs x1, mpidr_el1
  and x1, x1, #3
  cbz x1, 2f
1:
  wfe
  b 1b
2:
	ldr x0, =stack_top
	bic	sp, x0, #0xf				/* 16-byte alignment for ABI compliance */
	bl main
	bl .

src/linker.ld:


#include <Platform_def.h>

/*
OUTPUT_FORMAT("elf64-littleaarch64", "elf64-littleaarch64", "elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
*/


ENTRY(_start)

SECTIONS {
	. = 0x40000000;
	. = ALIGN(8);
    __text_start = .;
    .text : 
	{ 
		KEEP(*(.text.boot))
		STARTOBJ(.text)
		*(.text) 
	}

	/* shell_cmd_item 保存在这个段 */
    . = ALIGN(8);
    __shell_cmd_list_start = .;
     .ShellCmdList   ALIGN(8)  : { *(.ShellCmdList) }
    __shell_cmd_list_end = .;

	/* resource_item 保存在这个段 */
    . = ALIGN(8);
    __resource_item_start = .;
     .resource_item   ALIGN(8)  : { *(.ResourceList) }
    __resource_item_end = .;

    .rodata ALIGN(8) : {*(.rodata*)} 
    .data   ALIGN(8) : { *(.data) }

    . = ALIGN(8);
    __bss_start = .;
     .bss   ALIGN(8)  : { *(.bss)  *(COMMON) }
    __bss_end = .;

	/* resource 实际保存在这个段 */
    . = ALIGN(8);
	.extdata  ALIGN(8): {*(.extdata*)}

	/* 栈内存 */
	. = ALIGN(16);
	. = . + 1M; /* 4kB of stack memory => 1MB */
	stack_top = .;

	/DISCARD/ : { *(.dynsym) }
	/DISCARD/ : { *(.dynstr*) }
	/DISCARD/ : { *(.dynamic*) }
	/DISCARD/ : { *(.plt*) }
	/DISCARD/ : { *(.interp*) }
	/DISCARD/ : { *(.gnu*) }
}

#ifdef TPL
	/* tpl 运行在64kb 的iRam 中,体积不能超了,况且iRam分出来4kb做栈内存了,实际可用的内存就更少了,所以定个58kb的可用内存 */
	ASSERT( (__bss_start - __text_start) < (58*1024), 
	"
	编译出来的 tpl.bin 太大,iRam 装不下了,请编译为 spl => make spl
	");
#endif

src/coWork.h:

int c_func(int a, int b);

src/coWork.c:


extern int zig_func(int a, int b);

int c_func(int a, int b) {
	return zig_func(a, a) + b;
}

 startQemu.ps1:


[System.Console]::OutputEncoding = [System.Console]::InputEncoding = [System.Text.Encoding]::UTF8
& "d:\Program Files\qemu\qemu-system-aarch64.exe" -nographic -machine virt-6.2,gic-version=3,secure=on,virtualization=on -cpu cortex-a53 -m 1024 -semihosting -kernel ".\zig-out\bin\out.elf"

build.zig:

const Builder = @import("std").build.Builder;
const builtin = @import("builtin");
const std = @import("std");

pub fn build(b: *Builder) void {
    const target = .{
        .cpu_arch = .aarch64,
        .cpu_model = .{ .explicit = &std.Target.aarch64.cpu.cortex_a53 },
        .os_tag = .freestanding,
        .abi = .none,
    };

    // Standard release options allow the person running `zig build` to select
    // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall.
    const mode = b.standardReleaseOptions();

    const elf = b.addExecutable("out.elf", "src/main.zig");
    elf.addAssemblyFile("src/boot.S");
	elf.addIncludePath("src/"); // addIncludeDir 已经被官方标为deprecated,不建议使用
	elf.addCSourceFile("src/coWork.c", &[_][]const u8{"-std=c99"});
    elf.setTarget(target);
    elf.setBuildMode(mode);
    elf.setLinkerScriptPath(.{ .path = "src/linker.ld" });
	// --script

    const bin = b.addInstallRaw(elf, "out.bin", .{});
    const bin_step = b.step("bin", "Generate binary file to be flashed");
    bin_step.dependOn(&bin.step);

    b.default_step.dependOn(&elf.step);
    b.installArtifact(elf);
}

qemu运行截图:

通过 struct {} 定义类时,大括号里面的成员函数,
如果它的第一个参数的类型是类本身,
则此函数被当成类的实例的成员函数(比如代码中的 uart.getWriter ),
否则被当成类的静态函数,要通过 “类名.函数名的方式调用”,(比如代码中的 UART.putc )

zig 支持的目标cpu架构,可参考此目录:$(zig_install_dir)/lib/std/target/
也可能通过运行这条指令列出:zig  targets

参考:
GitHub - rbino/zig-stm32-blink: Use Zig to blink some LEDs

 Documentation - The Zig Programming Language

Documentation - Zig

0.10.0 Release Notes ⚡ The Zig Programming Language

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

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

相关文章

pyqt5中QGraphicsView弹出菜单

QPainter与Graphics View 架构的区别PyQt5 提供了两种绘图方法。一种是使用 QPainter 类在 QWidget 类提供的画布上画图&#xff0c;可以 绘制点、线、圆等各种基本形状&#xff0c;从而组成自己需要的图形。所有界面组件都是 QWidget 的子类&#xff0c; 界面上的按钮、编辑框…

74、【哈希表】leetcode——18. 四数之和(C++版本)

题目描述 原题链接&#xff1a;18. 四数之和 解题思路 思路与三数之和&#xff1a;15. 三数之和&#xff0c;区别之处在于&#xff1a; 1、多一层for循环&#xff0c;用于多加一个数。 四数之和就是在三数之和多加一个数&#xff0c;用前两个数相加&#xff0c;后面两个数继…

Hadoop之MapReduce

一、概述 MapReduce 核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的 分布式运算程序&#xff0c;并发运行在一个 Hadoop 集群上。 1、优缺点&#xff1a;优点&#xff1a;1&#xff09;MapReduce 易于编程 它简单的实现一些接口&#xff0c;就可以完成一个…

(day2)自学java综合练习

目录 1.卖飞机票 2.找质数 3.开发验证码 4.数组元素的复制 5.评委打分 6.数字加密 7.数字解密 8.抢红包 9.模拟双色球 10.二维数组 1.卖飞机票 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。按照如下规则计算机票价格&#xff1…

推荐两个好用的虚拟机、SSH 终端开源工具(Virtual Box、WindTerm)

笔者最近因一些变故&#xff0c;加上阳了&#xff0c;停更了一段时间&#xff0c;并提前回老家过年了。因并没有带笔记本电脑回去&#xff0c;故在折腾了一番老家电脑后&#xff0c;选择拥抱开源&#xff0c;使用一些开源的工具&#xff0c;而非习惯的 VMware Workstation 和 S…

Python3,区区10行代码,批量把图片插入Excel指定单元格中,省下时间去烫头发。

这里写目录标题1、引言2、代码实战2.1 代码示例2.2 遇到问题及处理方案2.2.1 遇到问题2.2.2 解决方案3、总结1、引言 小屌丝&#xff1a;鱼哥&#xff0c; 想请教你个问题。 小鱼&#xff1a;啥问题呢&#xff1f; 小屌丝&#xff1a;我想把图片插入到excel里面 小鱼&#xff…

AVS3变换之ISP和ISTS

ISP&#xff08;Implicit Selected Transform&#xff09;是AVS3中新增的针对intra块的变换工具&#xff0c;IST对intra块提供了两种可分离的变换核&#xff0c;编码器根据RDO选择最优的变换核&#xff0c;但是对于选中的变换核不在码流中传输其索引&#xff0c;而是将其索引隐…

今天给大家介绍一篇医院医疗管理系统的设计与实现(源码+论文)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据疫情当下&#xff0c;你想解决的问…

Java开发学习(三十七)----SpringBoot多环境配置及配置文件分类

一、多环境配置 在工作中&#xff0c;对于开发环境、测试环境、生产环境的配置肯定都不相同&#xff0c;比如我们开发阶段会在自己的电脑上安装 mysql &#xff0c;连接自己电脑上的 mysql 即可&#xff0c;但是项目开发完毕后要上线就需要该配置&#xff0c;将环境的配置改为…

亚马逊云科技 2022 re:Invent 的几个关键词:数据、云原生端到端、安全

一转眼&#xff0c;又是一年。2022 年云计算行业重要的技术趋势和方向里&#xff0c;亚马逊云科技一年一度的 re:Invent 大会是不可或缺的一环。 今年已经是 re:Invent 大会连续举办的第十一年&#xff0c;和往年一样&#xff0c;亚马逊云科技将一年的重磅技术观察和实践干货悉…

【数据结构】单链表 — 纯C实现单链表

目录&#x1f48c;前言一、定义1.概念2.特点3.优点4.缺点5.结点定义接口实现创建链表结点创建单个结点创建链表打印链表测试创建功能尾插尾删尾部插入尾部删除尾插尾删测试头插头删头部插入头部删除头插头删测试pos位的插入删除查找pos位置在pos位置前插入在pos位置后插入删除p…

CUDA和Compute Capability

Compute Capability 参考 指示GPU硬件能够支持的特性&#xff0c;可以被应用参考哪些特性可以运行。 这里能够找到不同Compute Capability对应的硬件特性。比如我的笔记本搭载了一块Geforce830m&#xff0c;Compute Capability为5.0&#xff0c;硬件特性为 另外有关技术细节比…

面试官问我HTTP,我真的是

面试官&#xff1a;今天要不来聊聊HTTP吧&#xff1f; 候选者&#xff1a;嗯&#xff0c;HTTP「协议」是客户端和服务器「交互」的一种通迅的格式 候选者&#xff1a;所谓的「协议」实际上就是双方约定好的「格式」&#xff0c;让双方都能看得懂的东西而已 候选者&#xff1…

2023-01-02 Echarts学习笔记(一) 基础概念和应用示例:折线图

文章目录0.什么是Echarts?1.常见使用场景2.使用Echarts的基本步骤3.应用示例:做一个折线图4.参考资料0.什么是Echarts? ECharts.js是 百度出品的一个开源 Javascript 数据可视化库 一个使用 JavaScript 实现的开源可视化库&#xff0c; 可以流畅的运行在 PC 和移动设备上&a…

【数据结构】二叉树递归算法代码总结

文章目录一、内容介绍二、算法总结2.1 二叉树结构2.2 完整代码2.3 输出结果三、Reference四、总结一、内容介绍 上一年备考数据结构中自己整理并验证过的二叉树递归算法。包括&#xff1a; 1、二叉树的创建&#xff1b; 2、二叉树的先、中、后序的递归遍历&#xff1b; 3、输出…

[项目说明]-基于人工智能博弈树,极大极小(Minimax)搜索算法并使用Alpha-Beta剪枝算法优化实现的可人机博弈的AI智能五子棋游戏。

个人选题项目 基于人工智能博弈树&#xff0c;极大极小(Minimax)搜索算法并使用Alpha-Beta剪枝算法优化实现的可人机博弈的AI智能五子棋游戏。 设计目标及主要内容 本系统是根据传统五子棋游戏的功能编写&#xff0c;其功能实现了基于AI人工智能算法实现智能的人机对弈五子棋…

Java jdk安装及环境配置

Java环境安装一、 jdk和jre的安装1、安装目录创建java文件夹2、java文件夹内创建jdk和jre3、解压下载好的jdk安装包二、环境变量的配置一、 jdk和jre的安装 首先下载jdk 1、安装目录创建java文件夹 2、java文件夹内创建jdk和jre 3、解压下载好的jdk安装包 双击运行解压的jdk …

Kali Linux中shutdown指令的用法3-2

2.4 屏蔽重启指令 -h参数表示屏蔽重启指令&#xff0c;使用如图6所示的指令&#xff0c;可以屏蔽reboot指令&#xff0c;该指令的作用为关闭&#xff08;poweroff&#xff09;系统。 图6 屏蔽重启指令 从图6中可以看出&#xff0c;-h屏蔽了--reboot。 需要注意的是&#xff…

关于OLTP 和OLAP 干货知识分享

OLTP 和 OLAP 这两个概念在十来年前、十几年前BI这个词还不是那么普及的时候&#xff0c;还经常放在一起做比较&#xff0c;现在已经很少再单独拿出来做对比了&#xff0c;但也总还是有人会问到&#xff0c;我在这里大概讲下两个概念的差别和联系。 什么是OLTP OLTP 英文全称…

81.Zabbix之Window服务器agent监控

Zabbix版本:6.2.3 1.官网上下载对应的agent Download Zabbix agents 我们下载Zabbix agent 2 2.配置Zabbix agent2 下载完成后,将压缩包复制到服务器,然后放在移至C盘目录下(其他目录也是可以的),然后进行解压。 3.修改配置文件 用文本编辑软件打开zabbix_agent2.c…