- 博客(41)
- 收藏
- 关注
原创 在Ubuntu 14.04上安装gcc-5
目的在国内的网络环境下,以超高速度在Ubuntu 14.04上安装gcc-5。环境全新的Ubuntu 14.04的Docker镜像。步骤将apt仓库设置为USTC的镜像(步骤可参考Ubuntu镜像使用帮助)。sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.listsed -i 's/security.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.
2021-01-06 13:02:09
715
原创 LLVM IR入门指南(7)——异常处理
在这篇文章中,我主要介绍的是LLVM IR中的异常处理的方法。主要的参考文献是Exception Handling in LLVM。异常处理的要求异常处理在许多高级语言中都是很常见的,在诸多语言的异常处理的方法中,try … catch块的方法是最多的。对于用返回值来做异常处理的语言(如C、Rust、Go等)来说,可以直接在高级语言层面完成所有的事情,但是,如果使用try … catch,就必须在语言的底层也做一些处理,而LLVM的异常处理则就是针对这种情况来做的。首先,我们来看一看一个典型的使用tr
2020-08-01 10:51:30
989
原创 LLVM IR入门指南(6)——函数
这篇文章我们来讲函数。有过汇编基础的同学都知道,在汇编层面,一个函数与一个控制语句极其相似,都是由标签组成,只不过在跳转时增加了一些附加的操作。而在LLVM IR层面,函数则得到了更高一层的抽象。定义与声明函数定义在LLVM中,一个最基本的函数定义的样子我们之前已经遇到过多次,就是@main函数的样子:define i32 @main() { ret i32 0}在函数名之后可以加上参数列表,如:define i32 @foo(i32 %a, i64 %b) { ret i32 0}
2020-07-25 11:12:58
920
原创 LLVM IR入门指南(5)——控制语句
我在之前汇编语言的教程中,是将跳转与函数放在一起讲的,因为在汇编语言中这两个概念几乎没有太大的区别。然而,到了LLVM IR中,这两者就有了比较大的区别。因此,在这篇文章中,我主要讲的是LLVM IR中控制语句的构造方法。汇编层面的控制语句在大多数语言中,常见的控制语句主要有四种:if … elseforwhileswitch在汇编语言层面,控制语句则被分解为两种核心的指令:条件跳转与无条件跳转(switch其实还有一些工作,之后会提到)。我们下面分别来看看在汇编层面是怎样实现控制语句的。
2020-07-24 09:20:56
1758
1
原创 LLVM IR入门指南(4)——类型系统
我们知道,汇编语言是弱类型的,我们操作汇编语言的时候,实际上考虑的是一些二进制串。但是,LLVM IR却是强类型的,在LLVM IR中所有变量都必须有类型。这是因为,我们在使用高级语言编程的时候,往往都会使用强类型的语言,弱类型的语言无必要性,也不利于维护。因此,使用强类型语言,LLVM IR可以更好地进行优化。基本的数据类型LLVM IR中比较基本的数据类型包括:空类型(void)整型(iN)浮点型(float、double等)空类型一般是作为不返回值的函数的返回类型,没有特别的含义,就代
2020-07-23 09:19:16
1820
原创 LLVM IR入门指南(3)——数据表示
LLVM IR和其它的汇编语言类似,其核心就是对数据的操作。这涉及到了两个问题:什么数据和怎么操作。具体到这篇文章中,我就将介绍的是,在LLVM IR中,是如何表示一个数据的。汇编层次的数据表示LLVM IR是最接近汇编语言的一层抽象,所以我们首先需要了解在计算机底层,汇编语言的层次中,数据是怎样表示的。谈到汇编层次的数据表示,一个老生常谈的程序就是#include <stdlib.h>int global_data = 0;int main() { int stack_dat
2020-07-21 10:11:19
1060
1
原创 LLVM IR入门指南(2)——Hello world
在系统学习LLVM IR语法之前,我们应当首先掌握的是使用LLVM IR写的最简单的程序,也就是大家常说的Hello world版程序。这是因为,编程语言的学习,往往需要伴随着练习。但是一个独立的程序需要许多的前置语法基础,那么我们不可能在了解了所有前置语法基础之后才完成第一个独立程序,否则在学习前置语法基础的时候,就没有办法在实际的程序中练习了。因此,正确的学习方式应该是,首先掌握这门语言独立程序的基础框架,然后每学习一个新的语法知识,就在框架中练习,并编译看结果是否是自己期望的结果。综上所述,学习一门
2020-07-20 09:48:48
895
原创 LLVM IR入门指南(1)——LLVM架构简介
LLVM是什么随着计算机技术的不断发展以及各种领域需求的增多,近几年来,许多编程语言如雨后春笋般出现,大多为了解决某一些特定领域的需求,比如说为JavaScript增加静态类型检查的TypeScript,为解决服务器端高并发的Golang,为解决内存安全和线程安全的Rust。随着编程语言的增多,编程语言的开发者往往都会遇到一些相似的问题:怎样让我的编程语言能在尽可能多的平台上运行怎样让我的编程语言充分利用各个平台自身的优势,做到最大程度的优化怎样让我的编程语言在汇编层面实现「定制」,能够控制如符号
2020-07-19 10:34:33
2381
原创 现代化程序开发笔记(17)——从HTTPS到iOS和Android的签名机制
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将从数字签名与证书开始,逐一介绍Web端、iOS端和Android端App的可信安全机制。不止于保密的三大问题我们知道,在现代科技领域,安全与密码学紧密相关。如果我们需要保证一个产品的安全,那么一定会去求助于密码学的工具。那么,密码学解决的究竟是什么问题?保密最基本的,密码学是为了保密。Alice和Bob在大庭广众下通信,但仍然不希望他人知道他
2020-07-12 15:32:05
354
原创 现代化程序开发笔记(16)——序列化与反序列化
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将介绍的是序列化与反序列化的相关技术与数据格式标准。需求背景众所周知,任何一个大型程序都需要和外界进行数据沟通交流,既需要接收外界传入的数据,也需要把内部计算得出的数据持久化。同时,随着程序规模的扩大和逻辑的复杂化,我们需要将数据妥善地组织才能进一步地接收或存储。比方说,我需要接收的数据同时包括一个人的姓名、性别、年龄,那么我们就需要与数据的发送方
2020-07-09 14:37:23
324
原创 现代化程序开发笔记(15)——各端数据库框架
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将介绍的是数据库在编程中的一些技术,以及iOS端和Android端的数据库框架。常见数据库众所周知,数据库就是我们在日常软件开发的时候用来存储、查询、修改持久性数据的技术。我通过之前自己做的几个小项目,积累了一些各个常见数据库的经验。键值对数据库要想记录数据,最最最直接的想法,就是使用键值对。我们可以把键值对数据库想象成一个字典,比如说,我要记
2020-07-06 14:35:21
572
原创 现代化程序开发笔记(14)——iOS+Android开发套件全解
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将介绍的是iOS和Android原生应用开发中所需要的套件。应用开发模式首先,我们要搞清楚,开发一个原生应用,究竟是一个怎样的模式。直白地说,就是:操作系统提供者将新系统的API和动态链接库打包成SDK发放给开发者开发者使用SDK开发应用开发者将应用投放到新系统中供用户使用这三步说起来很简单,但是在实际生产过程中,有许许多多的开发套件以
2020-07-02 13:59:52
332
原创 现代化程序开发笔记(13)——Git与Monorepo
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将简要介绍代码版本管理利器Git,同时谈一谈Monorepo的工作方式。代码版本管理工具作为开发者,我们通常会遇到两种写代码的场景:一种是写一个简单的程序或者demo,也许就几行,顶多也就两三个文件,要么用于自己的测试,要么用于展示,总之没有什么重要性,而且用完就被删了;另一种情况则是和他人合作,一起写一个很大的项目,并且会长期维护。第一种情况并不
2020-07-01 13:45:41
469
原创 现代化程序开发笔记(12)——泛型与多态
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将介绍的是泛型与多态。共性与标准我们为什么要使用泛型与多态?这些诡异的中文译名究竟指的是什么?我觉得,要解释这个问题,就需要指出我们实际编写项目时需要的共性与标准。假设我们在编写一个快餐店的程序。快餐店中,有服务员、薯条厨师、汉堡厨师和炸鸡厨师,在我们的程序中,这每一个职业都被实现为一个类,这个思路是很自然的。每个职业除了都有自己个性的工作,比如
2020-06-30 10:52:54
236
原创 现代化程序开发笔记(11)——异步编程杂谈
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将以我的理解从头开始梳理一遍异步编程。从网络IO开始作为一个服务器程序,最重要的就是维护网络的IO。我们知道,一个TCP连接对应一个TCP套接字,服务器程序需要做的,就是妥善处理这些套接字中的数据。粗略地说,一个服务器程序做的事如下:告诉内核自己监听了哪些套接字端点(socket endpoint)内核维护TCP连接,并将接收到的数据传递给服
2020-06-27 15:40:55
201
原创 现代化程序开发笔记(10)——空值处理
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将介绍的是空值的处理。问题的由来我们知道,程序中的大部分变量,要么分配在栈区要么分配在堆区。分配在堆区的变量,总是需要一个指针来管理。在C语言中,我们可以这么写:struct MyStruct *my_struct = (struct MyStruct *)malloc(sizeof(struct MyStruct));来在堆区创建一个变量,
2020-06-25 10:49:38
240
原创 现代化程序开发笔记(9)——异常处理
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将讨论的是主流的异常处理的方法。首先,我们要知道,异常处理通常分为两种:一种是比如把0作为分母,或者把NULL解引用,这类都属于操作系统或底层硬件告诉你这不该做的;而另一种则是开发者自己编写程序的时候,发现了不符合程序需求的地方,比如说从数据库查询一条数据,结果却返回了两条记录,这种是由开发者自己提醒自己做了不该做的事,程序出了问题。我这篇文章主要讨
2020-06-24 13:59:32
208
原创 现代化程序开发笔记(8)——通俗易懂的函数式编程入门
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将尽量用通俗易懂的方法,介绍函数式编程的入门知识。什么是函数式编程作为一个开发者,面对一个需求,我们掌握的知识常常是一定能完成这个需求,但是完成的方法多种多样,我们需要选择更好的技术来完成这些需求。就比如说我们是做汉堡的厨师,那么只要具有这方面的知识,这汉堡总能做成,无非是将制作好的肉、酱、蔬菜放在两片面包之间。但是,完成这个汉堡的手法有多种,比如
2020-06-23 16:26:09
359
原创 现代化程序开发笔记(7)——闭包
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将讨论的是现代语言中的闭包。函数起名之痛在现代语言中,函数是一等公民的思想几乎贯彻在了每一个编程语言中,函数应该和变量一样,能够自由地作为参数和返回值在函数间传递。比方说,一个游戏的开发者在写代码的时候发现,有好几种怪物的代码都极其类似,但只有其进行打斗的样子不同。因此,开发者将这几个怪物的代码封装成同一个函数monster,那么怎样区别这几种怪物
2020-06-22 14:05:31
236
原创 现代化程序开发笔记(6)——赋值语义
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将讨论的是现代语言的各种赋值语义。背景无论我们使用什么语言进行编程开发,都会遇到一个基本的问题,比如说以C++为例:struct MyStruct { int foo; };void foo() { MyStruct my_struct1, my_struct2; mystruct1.foo = 1; my_st
2020-06-21 14:39:46
297
原创 现代化程序开发笔记(5)——生命周期管理
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将讨论的是现代语言的变量生命周期管理机制。背景我们知道,在一个程序运行的时候,任何一个使用的变量在内存中都会占有一定的空间。而除去特殊的静态数据区,在大多数操作系统中,变量要么储存在栈上,要么储存在堆上。创造变量有两种方式,一种是直接在块级作用域内声明局部变量,这种变量是分配在栈上的,另一种则是调用操作系统提供的内存分配函数如malloc等,这种变
2020-06-20 16:22:12
205
原创 现代化程序开发笔记(4)——包管理工具
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我会就项目构建工具和包管理工具做一些讨论,先讨论一个理想的包管理工具应该做到什么,再就一些具体语言的相应工具作一些对比。刀耕火种的时代在编程语言最早出现的时代,大家写的项目都不大,开发者手边,只有用来写代码的编辑器,和用来编译结果的编译器(假设链接器已经包含在编译器内了)。打个比方来说,最早期的开发者,就像是刚开业的快餐店,只制作并售卖一种食物。开发
2020-06-19 15:47:50
236
原创 现代化程序开发笔记(3)——多文件与模块
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在这篇文章中,我将对现代编程语言的多文件和模块部分进行一些介绍。模块化编程随着现代编程开发项目的代码量越来越大,参与开发维护的人数越来越多,模块化编程这一理念变得十分重要。就像我所说的,模块化编程实际上是一个理念,它倡导的是开发者利用各种手段,将不同作用的代码块隔离。比方说,众所周知,巫师三的两个核心功能是昆特牌功能和与女术士增进感情的功能。假设我们是简陋版巫师三
2020-06-18 15:14:28
269
原创 现代化程序开发笔记[2]——编译方法
本系列文章以我的个人博客的搭建为线索(GitHub 仓库:Evian-Zhang/evian-blog),记录我在现代化程序设计中的一些笔记。在本篇文章中,我想就编译方法作一些讨论。运行平台简介我们的计算机执行一个程序,其本质的过程如下:我们告诉操作系统,要执行某个程序操作系统查看该程序,并告诉CPU如何执行这个程序CPU开始执行程序在这个过程中,我们可以发现,影响一个程序执行的因素有两个:操作系统决定这个程序该如何执行,以及CPU根据程序执行相应的指令。“操作系统决定这个程序该如何运行”
2020-06-17 11:31:25
277
原创 现代化程序开发笔记[1]——简介
转眼大学生活已经快过去三年了,我的程序开发知识也获得了许多。因此,正好这段时间比较轻松,我就重构了一下我原来很简陋的个人博客,并且开发了Web端(地址Evian张的博客)、iOS端和Android端,并将代码开源在GitHub上Evian-Zhang/evian-blog。在开发的过程中,我也对之前的知识进一步地巩固,并获得了新的经验。因此,我打算以我的博客开发为线索,记录现代化程序开发的笔记,并分享给大家。由于是个人博客,所以相比于比较老旧的语言、框架,我更加喜欢尝试一些全新的,口碑好的技术。目前我的博
2020-06-17 11:28:58
188
原创 解决Alpine上Rust无法使用过程宏的方法
背景过程宏Rust的过程宏(Procedural macro)是一个挺好的设计,我们实际工程中的许多地方都会用到它。比如说:使用serde序列化时#[derive(Serialize)]struct Foo { bar: usize}使用actix进行路径匹配时#[get("/")]pub fn index() -> String { "Hello...
2020-05-05 10:06:20
1142
原创 多平台命令行工具的发布方法
最近,我用Rust写了一个命令行工具(Evian-Zhang/Wispha,也可以看我相关的知乎文章Wispha – 轻松展示项目结构布局)。得益于Rust自身的特性,这个命令行工具不需要更改代码,只需要在相应的平台上编译一遍,就可以实现多平台版本。相信许多个人开发者有和我类似的经历,开发了多平台的命令行工具以后,却不知道如何分发(distribute)自己的代码,GitHub releases里...
2020-03-13 15:46:36
218
原创 macOS上的汇编入门(十三)——从编译到执行
作为这一系列文章中的最后一篇,这篇文章我打算讨论的是从编译到执行的全过程。因为许多地方都是要有了汇编的基础知识以后才方便讨论,所以我把它放到了最后一篇。编译编译并不是对汇编代码来说的,而是对更高级的语言,如C、C++来说的。如果一个语言最终的编译结果是可执行文件,那么它一定会先被编译为汇编语言,然后再被汇编、链接为可执行文件。对于C和C++来说,大部分的编译器都支持输出汇编结果。比如说对于te...
2019-07-23 11:14:19
505
原创 macOS上的汇编入门(十二)——调试
随着我们编写的汇编程序越来越复杂,往往就需要调试。对于汇编语言而言,常见的调试器有LLDB和GDB. 由于我比较喜欢用LLVM系列的产品,因此,在这篇文章中我主要介绍的是LLDB来调试汇编语言的方法。关于详细的LLDB的使用方法,大家可去官网lldb.llvm.org查看。同时,在新版本的macOS上使用GDB是一件比较麻烦的事,需要证书签名。关于使用方法请参见我之前的文章在macOS10.14...
2019-07-22 10:33:09
733
原创 macOS上的汇编入门(十一)——系统调用
在上一篇文章中,我们更深入地讨论了关于汇编语言函数方面的知识,同时也介绍了如何调用系统库libSystem.dylib的函数。在这篇文章中,我们讨论的是另一种系统提供的函数——系统调用。什么是系统调用所谓系统调用(System call), 就是指操作系统提供的接口。我们知道,现代的操作系统分为内核态和用户态。我们平时的汇编语言的执行过程中,都是在用户态执行的。但是,有一些核心的功能,如文件的...
2019-07-21 11:04:05
957
原创 macOS上的汇编入门(十)——再探函数
在上一篇文章中,我们简要地谈了在汇编语言中是如何实现函数功能的,即用call和ret. 在这篇文章中,我们将更深入地探讨关于汇编语言中函数的话题。调用约定汇编语言中的函数,实质只是一个标签所代表的内存地址。它不像其他高级语言一样,有完整的函数原型体系。比如说,在C语言中,int func(int a, char *b)可以让我们知道,这个函数接受两个参数,第一个是int类型的,第二个是char...
2019-07-20 12:43:55
405
原创 macOS上的汇编入门(九)——跳转与函数
通过之前的几篇文章,我们了解了汇编语言的基本语法和变量的使用、寻址方式等,但我们的程序到目前为止,都只局限在_main内,既没有函数调用,也没有控制结构,进了_main以后一条路走到retq. 在这篇文章中,我主要介绍的是汇编语言中的控制结构——跳转,与函数调用。不过在介绍这两个之前,首先需要介绍的是跳转与函数调用的基础——标签。标签标签(Label), 是汇编语言中一个重要的组成部分。我们之...
2019-07-19 14:36:10
451
原创 macOS上的汇编入门(八)——寻址方式与全局变量
在上一篇文章中,我们讨论了汇编语言中如何定义字面量与局部变量。在这篇文章中,我们将继续讨论,如何在汇编语言中定义C语言中的全局变量。在讨论全局变量之前,我们首先需要介绍一下寻址方式。寻址方式所谓寻址方式,就是已知地址如何获得该地址对应的内存单元内的值。在上一篇文章中,我们实质已经用到了寻址方式。比如说,已知栈顶的地址存储在rsp内,那么我们是通过(%rsp)获得对应位置的内存单元的值的。一般来...
2019-07-18 12:09:19
945
原创 macOS上的汇编入门(七)——字面量与局部变量
在上一篇文章中,我们分析了第一个汇编程序。# exit.s .section __TEXT,__text .globl _main_main: movq $0, %rax retq这个汇编程序是我们所有汇编程序的框架,因为它实现了程序进入和程序退出的功能。我们接下来所有的程序都是在这个程序的基础上进行修改。在这篇文章中,我主要介绍的是...
2019-07-17 13:29:53
615
原创 macOS上的汇编入门(六)——汇编语言初识
上一篇文章中初步介绍了汇编语言的编辑器、汇编器与链接器,又让大家尝试了第一个程序。在本篇文章中,我们主要解释一下第一个程序。# exit.s .section __TEXT, __text .globl _main_main: movq $0, %rax retq注释程序的第一行是注释。在macOS的as汇编器语法下,注释由#开头,在...
2019-07-16 11:02:54
1270
原创 macOS上的汇编入门(五)——第一个汇编程序
通过前几篇文章,我们逐步建立了学习汇编语言之前需要的基础知识。接下来,在这篇文章中,我们开始编写我们的第一个汇编程序了。编辑器,汇编器与链接器工欲善其事,必先利其器。我们编写汇编语言,至少需要编辑器、汇编器和链接器。编辑器,就是提供语法高亮、智能缩进、自动补全等功能的文本编辑软件,汇编器与链接器则是汇编语言需要的核心装备,其功能我会在接下来的几篇文章中提到。我使用的编辑器是Visual Stu...
2019-07-15 10:48:52
1359
4
原创 macOS上的汇编入门(四)——操作系统基础
当我们学习汇编的时候,除了数学基础以及硬件基础以外,操作系统的基础也是一个至关重要的环节。汇编语言本质上就是机器码的human-readable的版本,而硬件相同,则同一个程序的机器码一定相同。那么我们为什么还要研究操作系统呢?这是因为,我们通过汇编语言,最终得到的可执行文件是与操作系统有关的,是操作系统来决定我们如何装载、执行这些可执行文件。此外,不同操作系统提供的库、系统调用并不完全相同。因此...
2019-07-14 15:33:11
917
原创 macOS上的汇编入门(三)——硬件基础
在上一篇文章中,我们讲了关于进制、补码和逻辑运算的数学基础。在这篇文章中,我们主要讨论的是硬件基础。由于汇编语言实际上是底层硬件的一个抽象,因此,我并不想太多地涉及底层硬件,只想大致讲一下硬盘-内存-CPU的这个三级结构。但这里要指出的是,实际上硬件层面远不止这么简单,还有一二三级缓存等复杂的结构。CPU、内存与硬盘打开我们的Mac的系统信息,我们可以看到处理器和内存型号:在磁盘工具中,我...
2019-07-12 12:02:27
640
1
原创 macOS上的汇编入门(二)——数学基础
在正式介绍汇编语言之前,我会先用几篇文章讲一些数学基础和硬件基础。如果读者已经具备了一定的知识基础,可以直接跳过这些文章去汇编语言部分。二进制,八进制与十六进制在计算机底层的软件层面,我们通常采用二进制,八进制或十六进制来记录数字,其中最常用的是十六进制。所谓nnn进制,就是从0开始数,逢nnn进1. 比如说二进制,就是从0开始数,到1,然后到2的时候进1变成10. 八进制也是类似,但是到了十...
2019-07-11 12:55:47
1000
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人