1.使用指南

这里主要介绍 mbedtls 程序的基本使用流程,并针对使用过程中经常涉及到的结构体和重要 API 进行简要说明。

mbedtls 的基本工作流程如下所示:

  • 初始化 SSL/TLS 上下文
  • 建立 SSL/TLS 握手
  • 发送、接收数据
  • 交互完成,关闭连接

menuconfig 配置说明

获取 mbedtls 软件包或者修改用户配置都需要使用 menuconfig。需要用户打开 ENV 工具,并将目录切换到您所用的 BSP 目录,使用 menuconfig 命令打开配置界面。

RT-Thread online packages → security packages 中选择 mbedtls 软件包,操作界面如下图所示:

详细的配置介绍如下所示:

RT-Thread online packages --->security packages  --->Select Root Certificate  --->      # 选择证书文件[*] mbedtls: An portable and flexible SSL/TLS library # 打开 mbedtls 软件包[*]   Store the AES tables in ROM      # 将 AES 表存储在 ROM 中(2)   Maximum window size used         # 用于点乘的最大“窗口”大小(2-7)(3584) Maxium fragment length in bytes # 配置数据帧大小[*]   Enable a mbedtls client example  # 开启 mbedtls 测试例程[ ]   Enable Debug log output          # 开启调试 log 输出version (latest)  --->           # 选择软件包版本,默认为最新版本
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • Using all default CA 配置选项会将 certs/default 目录下的所有预置证书加入编译,将占用很大的内存
  • Using user CA 配置选项允许用户将自己需要的证书文件加入编译,需要用户将证书文件拷贝到 certs 根目录

选择合适的配置项后,使用 pkgs --update 命令下载软件包并更新用户配置。

功能配置说明

mbedtls 功能模块的开启与关闭定义在 mbedtls/config.h 和 ports/inc/tls_config.h 文件中

mbedtls/config.h 是 mbedtls 源码里提供的配置文件,ports/inc/tls_config.h 是 RT-Thread 基于 mbedtls 源码中的配置文件进行的裁剪和适配。

最终,用户使用的是 RT-Thread 提供的配置文件 ports/inc/tls_config.h

用户可以通过文件中的宏来使能或失能部分不需要使用的功能模块,从而将 mbedtls 配置到合适的尺寸。

证书配置说明

  • 预置的 CA 证书文件存放在 certs/default 目录中
  • 用户增加的 CA 证书文件存放在 certs 根目录中

certs/default 目录中已经包含了大多数 CA 根证书,如果您使用的根证书不在该文件夹内,需要用户将自己的 PEM 格式的 CA 证书拷贝 certs 根目录下。(仅支持 PEM 格式证书,不支持 DER 格式证书)。

该证书文件中已经包含了大多数 CA 根证书,,参考后边的 添加新证书 章节。

初始化 TLS 会话

typedef struct MbedTLSSession
{char* host;char* port;
<span class="token keyword">unsigned</span> <span class="token keyword">char</span> <span class="token operator">*</span>buffer<span class="token punctuation">;</span>               <span class="token comment">// 公用数据缓冲区</span>
size_t buffer_len<span class="token punctuation">;</span>                   <span class="token comment">// 缓冲区大小</span>mbedtls_ssl_context ssl<span class="token punctuation">;</span>             <span class="token comment">// 保存 ssl 基本数据</span>
mbedtls_ssl_config conf<span class="token punctuation">;</span>             <span class="token comment">// 保存 ssl 配置信息</span>
mbedtls_entropy_context entropy<span class="token punctuation">;</span>     <span class="token comment">// 保存 ssl 熵配置</span>
mbedtls_ctr_drbg_context ctr_drbg<span class="token punctuation">;</span>   <span class="token comment">// 保存随机字节发生器配置</span>
mbedtls_net_context server_fd<span class="token punctuation">;</span>       <span class="token comment">// 保存文件描述符</span>
mbedtls_x509_crt cacert<span class="token punctuation">;</span>             <span class="token comment">// 保存认证信息</span>

} MbedTLSSession;

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

MbedTLSSession 用于保存建立 TLS 会话连接时的配置信息,在 TLS 上下文中传递使用。用户在使用建立 TLS 会话前,必须定义一个存储会话内容的结构体,如下所示:

static MbedTLSSession *tls_session = RT_NULL;
tls_session = (MbedTLSSession *)malloc(sizeof(MbedTLSSession));

tls_session->host = strdup(MBEDTLS_WEB_SERVER);
tls_session->port = strdup(MBEDTLS_WEB_PORT);
tls_session->buffer_len = MBEDTLS_READ_BUFFER;
tls_session->buffer = malloc(tls_session->buffer_len);

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里需要设置 SSL/TLS 服务器的 host 和 port,以及数据接收 buffer 等配置。

初始化 SSL/TLS 客户端

应用程序使用 mbedtls_client_init 函数初始化 TLS 客户端。

初始化阶段按照 API 参数定义传入相关参数即可,主要用来初始化网络接口、证书、SSL 会话配置等 SSL 交互必须的一些配置,以及设置相关的回调函数。

示例代码如下所示:

char *pers = "hello_world"; // 设置随机字符串种子
if((ret = mbedtls_client_init(tls_session, (void *)pers, strlen(pers))) != 0)
{rt_kprintf("MbedTLSClientInit err return : -0x%x\n", -ret);goto __exit;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

实际调用的 mbedtls 库函数如下所示:

初始化 SSL/TLS 客户端上下文

应用程序使用 mbedtls_client_context 函数配置客户端上下文信息,包括证书解析、设置主机名、设置默认 SSL 配置、设置认证模式(默认 MBEDTLS_SSL_VERIFY_OPTIONAL)等。

示例代码如下所示:

if((ret = mbedtls_client_context(tls_session)) < 0)
{rt_kprintf("MbedTLSCLlientContext err return : -0x%x\n", -ret);goto __exit;
}
  • 1
  • 2
  • 3
  • 4
  • 5

建立 SSL/TLS 连接

使用 mbedtls_client_connect 函数为 SSL/TLS 连接建立通道。这里包含整个的握手连接过程,以及证书校验结果。

示例代码如下所示:

if((ret = mbedtls_client_connect(tls_session)) != 0)
{rt_kprintf("MbedTLSCLlientConnect err return : -0x%x\n", -ret);goto __exit;
}
  • 1
  • 2
  • 3
  • 4
  • 5

读写数据

向 SSL/TLS 中写入数据

示例代码如下所示:

static const char *REQUEST = "GET https://www.howsmyssl.com/a/check HTTP/1.0\r\n""Host: www.howsmyssl.com\r\n""User-Agent: rtthread/3.1 rtt\r\n""\r\n";

while((ret = mbedtls_client_write(tls_session, (const unsigned char *)REQUEST,strlen(REQUEST))) <= 0)
{
if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
rt_kprintf(“mbedtls_ssl_write returned -0x%x\n”, -ret);
goto __exit;
}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

从 SSL/TLS 中读取数据

示例代码如下所示:

memset(tls_session->buffer, 0x00, tls_session->buffer_len);
ret = mbedtls_client_read(tls_session, (unsigned char *)tls_session->buffer,len);
if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret ==MBEDTLS_ERR_SSL_WANT_WRITE)continue;

if(ret MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
break;
if(ret < 0)
{
rt_kprintf(“mbedtls_ssl_read returned -0x%x\n”, -ret);
break;
}
if(ret 0)
{
rt_kprintf(“connection closed\n”);
break;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

注意,如果读写接口返回了一个错误,必须关闭连接。

关闭 SSL/TLS 客户端连接

客户端主动关闭连接或者因为异常错误关闭连接,都需要使用 mbedtls_client_close 关闭连接并释放资源。

示例代码如下所示:

mbedtls_client_close(tls_session);
  • 1
  • 2

mbedtls 使用范式

参考示例程序 samples/tls_app_test.c

添加新证书

CA 证书有两种常用格式 PEM 格式DER 格式,目前 RT-Thread mbedtls 仅支持 PEM 格式 的证书文件。

  • PEM 格式证书

    PEM 格式证书 通常是以 .pem.cer 后缀名结尾的文件。

    使用文本编辑器打开后,文件内容以 -----BEGIN CERTIFICATE----- 开头,以 -----END CERTIFICATE----- 结尾。

  • DER 格式证书

    DER 格式证书 是二进制文件类型。

根证书样式

双击 .cer 后缀名结尾的 CA 文件(Windows系统)可以看到证书的签发机构和有效期,如下图所示:

PEM 格式 格式的证书文件内容内容样式如下所示:

-----BEGIN CERTIFICATE-----
MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
-----END CERTIFICATE-----
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

获取根证书

  • 直接向服务商索取

    向服务商索取 base64 编码 X.509 编码的 PEM 格式 证书文件。

  • 从服务商网站导出

    • 浏览器打开服务商网站,以 https://www.rt-thread.org/ 为例

    • 点击浏览器地址栏的 安全,然后点击证书

    • 查看证书详细信息

    • 根证书导出向导

    • 选择导出 Base64 编码证书

    • 选择证书存储位置

    • 完成证书文件导出

      完成证书导出,假设证书文件名为 USER_ROOT_CA.cer

导入证书

  • 使用文本编辑器打开上个步骤导出的根证书文件 USER_ROOT_CA.cer
  • 拷贝 USER_ROOT_CA.cer 文件到 certs 根目录
  • 使用 scons 命令重新编译

注:

scons 命令编译后,会自动将证书文件拷贝到 const char mbedtls_root_certificate[] 数组中。

2.工作原理

mbedtls** 软件包是对 SSL/TLS 协议的实现。SSL(安全套接层)和 TLS(传输安全层)均是为了保证传输过程中信息的安全,是在明文传输基础上进行的加密,然后以密文的形式传输数据。

mbedTLS 建立安全通信连接需要经过以下几个步骤:

  • 初始化 SSL/TLS 上下文
  • 建立 SSL/TLS 握手
  • 发送、接收数据
  • 交互完成,关闭连接

其中,最关键的步骤就是 SSL/TLS 握手 连接的建立,这里需要进行证书校验。
SSL/TLS 握手流程

DTLS 握手流程

为了避免拒绝服务攻击,DTLS采用和IKE一样的无状态 cookie 技术。当客户端发送 client hello 消息后,服务器发送 HelloVerifyRequest 消息,这个消息包含了无状态 cookie。客户端收到之后必须重传添加上了 cookie 的 clienthello。

DTLS 握手流程如下图所示:

3.示例程序

该示例程序提供了一个简单的 TLS client,与测试网站建立 TLS 连接并获取加密数据。

示例文件

示例程序路径 说明
samples/tls_app_test.c TLS 测试例程
例程工作流程
本例程使用了 RT-Thread 官方 TLS 测试网站 www.rt-thread.org,使用 mbedtls_client_write 函数发送 HTTP 测试请求,成功后,该网站会返回文本数据,测试例程将解析后的数据输出到控制台。

例程使用的 HTTP 请求数据如下所示

"GET /download/rt-thread.txt HTTP/1.0\r\n"
"Host: www.rt-thread.org\r\n"
"User-Agent: rtthread/3.1 rtt\r\n"
"\r\n";
  • 1
  • 2
  • 3
  • 4

mbedTLS 测试例程的基本工作流程如下所示

client连接测试网站 www.rt-thread.org

client 和 server 握手成功

client 发送请求

server 回应请求

TLS 测试成功/失败

同步设备时间

SSL/TLS 服务器进行证书校验的过程中,会对当前发起校验请求的时间进行认证,如果时间不满足服务器的要求,就会校验证书失败。因此,我们需要为设备同步本地时间。

  • 方式一: 使用 date 命令

    未同步过时间的设备输入 date 命令后如下所示:

msh />date
Thu Jan  1 00:00:06 1970
  • 1
  • 2

使用 date 设置当前时间,如下所示:

msh />date 2018 08 02 12 23 00
msh />date
Thu Aug  2 12:23:01 2018
msh />
  • 1
  • 2
  • 3
  • 4
  • 方式二: 使用 NTP 同步网络时间

    该方式需要依赖 NTP 工具包,使用 menuconfig 配置获取,如下所示:

RT-Thread online packages --->IoT - internet of things  --->-*- netutils: Networking utilities for RT-Thread  --->-*-   Enable NTP(Network Time Protocol) client(8)     Timezone for calculate local time(cn.ntp.org.cn) NTP server name
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

使用命令 ntp_sync 同步网络时间

msh />ntp_sync
Get local time from NTP server: Thu Aug  2 14:31:30 2018
The system time is updated. Timezone is 8.
msh />date
Thu Aug  2 14:31:34 2018
  • 1
  • 2
  • 3
  • 4
  • 5

启动例程

在 MSH 中使用命令 tls_test 执行示例程序,成功建立 TLS 连接后,设备会从服务器拿到一组密码套件,设备 log 如下所示:

msh />tls_test
MbedTLS test sample!
Memory usage before the handshake connection is established:
total memory: 33554408
used memory : 20968
maximum allocated memory: 20968
Start handshake tick:3313
[tls]mbedtls client struct init success...
[tls]Loading the CA root certificate success...
[tls]mbedtls client context init success...
msh />[tls]Connected www.rt-thread.org:443 success...
[tls]Certificate verified success...
Finish handshake tick:6592
MbedTLS connect success...
Memory usage after the handshake connection is established:
total memory: 33554408
used memory : 45480
maximum allocated memory: 50808
Writing HTTP request success...
Getting HTTP response...
HTTP/1.1 200 OK
Server: nginx/1.10.3 (Ubuntu)
Date: Fri, 31 Aug 2018 08:29:24 GMT
Content-Type: text/plain
Content-Length: 267
Last-Modified: Sat, 04 Aug 2018 02:14:51 GMT
Connection: keep-alive
ETag: "5b650c1b-10b"
Strict-Transport-Security: max-age=1800; includeSubdomains; preload
Accept-Ranges: bytes

RT-Thread is an open source IoT operating system from China, which has strong scalability: from a tiny kernel running on a tiny core, for example ARM Cortex-M0, or Cortex-M3/4/7, to a rich feature system running on MIPS32, ARM Cortex-A8, ARM Cortex-A9 DualCore etc.

MbedTLS connection close success.

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

4.常见问题

证书验证失败

[tls]verification info: ! The CRL is not correctly signed by the trusted CA
  • 1
  • 2
  • 原因

    mbedtls 包中支持多种主流 CA 机构根证书,部分 CA 机构未支持

  • 解决方法

    若测试其他 TLS 网站证书验证失败,手动获取测试网站根证书(Root Cerificate)添加到mbedtls/tls_cerificate.c文件中

证书时间错误

[tls]verify peer certificate fail....
[tls]verification info:   ! The certificate validity starts in the future
  • 1
  • 2
  • 3
  • 原因

    TLS 握手是证书验证需要时间的验证,本地时间获取有误导致

  • 解决方式

    检查 RTC 设备是否支持,检查 RT_USING_RTC 宏是否打开,校准设备时间。建议使用 NTP 同步本地时间。

证书 CN 错误

    verification info: ! The certificate Common Name (CN) does not match with the expected CN
  • 1
  • 2
  • 原因

    测试其他 TLS 网站时,若输入域名不符合证书的 Common Name(CN)出现 CN 验证失败问题

  • 解决方法

    检查输入域名和证书中 CN 是否匹配或输入 IP 地址

0x7200 错误

  • 原因

    部分原因是因为 mbedTls 收到了大于缓冲区大小的数据包

  • 解决方法

    menuconfig 配置增加数据帧大小 ( Maxium fragment length in bytes )

RT-Thread online packages --->security packages  --->Select Root Certificate  --->      # 选择证书文件[*] mbedtls: An portable and flexible SSL/TLS library  ---[*]   Store the AES tables in ROM(2)   Maximum window size used(6144) Maxium fragment length in bytes # 配置数据帧大小(0x7200 错误可尝试增加该大小)[*]   Enable a mbedtls client exampleversion (latest)  --->
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

参考

  • mbedTLS官方网站:https://tls.mbed.org/
  • ARMmbed GitHub:mbedtls

mbedtls学习2.mbedtls从0使用指南相关推荐

  1. 转:mbedtls学习2.mbedtls从0使用指南

    1.使用指南 这里主要介绍 mbedtls 程序的基本使用流程,并针对使用过程中经常涉及到的结构体和重要 API 进行简要说明. mbedtls 的基本工作流程如下所示: 初始化 SSL/TLS 上下 ...

  2. 《果壳中的C# C# 5.0 权威指南》 (09-26章) - 学习笔记

    <果壳中的C# C# 5.0 权威指南> ========== ========== ========== [作者] (美) Joseph Albahari (美) Ben Albahar ...

  3. 《果壳中的C# C# 5.0 权威指南》 (01-08章) - 学习笔记

    <果壳中的C# C# 5.0 权威指南> ========== ========== ========== [作者] (美) Joseph Albahari (美) Ben Albahar ...

  4. 深度学习框架集成平台C++ Guide指南

    深度学习框架集成平台C++ Guide指南 这个指南详细地介绍了神经网络C++的API,并介绍了许多不同的方法来处理模型. 提示 所有框架运行时接口都是相同的,因此本指南适用于所有受支持框架(包括Te ...

  5. 深度学习语义分割理论与实战指南

    本文来自微信公众号[机器学习实验室] 深度学习语义分割理论与实战指南 1 语义分割概述 2 关键技术组件 2.1 编码器与分类网络 2.2 解码器与上采样 2.2.1 双线性插值(Bilinear I ...

  6. 限时团购,6.5折:《C# 7.0 核心技术指南》

    大家好,经过近两年的翻译,<C# 7.0 核心技术指南>终于和大家见面了.全书由 ThoughtWorks 高级咨询师,资深 .NET 专家刘夏翻译.作为一本第七次再版的图书,此次翻译对书 ...

  7. 深度学习语义分割理论与实战指南.pdf

    深度学习语义分割理论与实战指南 V1.0 版本已经完成,主要包括语义分割概述.关键技术组件.数据模块.经典分割网络与架构.PyTorch基本实战方法等五个部分. 获取方式: 扫描关注下方公众号回复 语 ...

  8. python入门指南-python3.6.0入门指南(官方版).pdf

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp计算机&nbsp>&nbspPython python3.6.0入门指南(官方版).pdf7 ...

  9. ActionScript 3.0权威指南

    ActionScript 3.0权威指南 作者:  乔珂  译者: 无  定 价:  89.00元(含光盘1张)  页码:  840  出版时间:  2008-07  ISBN号:  97871210 ...

最新文章

  1. 用户未登录重定向到登录界面_Linux 用户登录记录
  2. all index range ref eq_ref const system 索引type说明
  3. Python语法点滴
  4. Calendar是日历类
  5. linux platform 驱动模型分析
  6. centos redis php扩展,手动在centos下安装redis及php扩展
  7. Atitit 编程语言原理与概论attilax总结
  8. Qt 环境下MAPX组件的编程
  9. 手机中CAD图纸发送到电脑上后打不开了怎么办?
  10. PMP考试中一些解题思路
  11. pytorch 注意力机制
  12. !!!python 100行代码编写【Google 图片搜索爬取工具】多线程
  13. 从Docker镜像创建Singularity镜像(SIF文件)
  14. 树莓派-内核启动报错mmc0: error -5 whilst initialising MMC card
  15. 推荐几款HTML5开发工具
  16. 深度学习CNN模型预测电影评论中的情感问题
  17. CSS基础(新手入门教程)
  18. xp计算机内存条启动,加快XP启动
  19. memset, fill 对bool,int 赋值的效率
  20. 使用普通摄像头,轻松实现精准动作捕捉能力

热门文章

  1. VCS makefile文件
  2. hdu 5148 树形dp,分组背包
  3. 9006 - ProxySQL Error: connection is locked to hostgroup 2 but trying to reach hostgroup 1
  4. 智源发布《人工智能的认知神经基础白皮书》,一览“AI×脑科学”前沿
  5. 全球及中国视频会议摄像机行业市场运营模式与投资战略规划研究报告2022-2028年
  6. Mysql初始化的命令
  7. Python函数——Numpy size()
  8. 天朝皇叔:学习笔记 Qt 连接数据库sql server
  9. 在360个人图书馆中实现复制
  10. Linux-C C语言编译过程