<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.8.5">Jekyll</generator><link href="https://www.bahutou.cn/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.bahutou.cn/" rel="alternate" type="text/html" /><updated>2020-02-16T10:12:01+08:00</updated><id>https://www.bahutou.cn/feed.xml</id><title type="html">bahutou</title><subtitle>bahutou的个人博客</subtitle><author><name>Linc Zhang</name></author><entry><title type="html">STM32程序的编译、链接和启动分析</title><link href="https://www.bahutou.cn/2018/05/28/compile-link-loader-boot/" rel="alternate" type="text/html" title="STM32程序的编译、链接和启动分析" /><published>2018-05-28T00:00:00+08:00</published><updated>2018-05-28T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/05/28/compile-link-loader-boot</id><content type="html" xml:base="https://www.bahutou.cn/2018/05/28/compile-link-loader-boot/">&lt;p&gt;本篇文章以STM32为硬件平台，使用GNU GCC作为开发工具，详细分析Compile 、Link 、Loader的过程以及Image(二进制程序)启动的详细分析。整个过程分析涉及到RW可读写段从Flash到Mem的Copy，BSS段的初始化，Stack和Heap的初始化，C库函数移植、利用Semihosting 实现基本的IO等内容。基本可以让你从更深刻的层面理解Source -&amp;gt; Compile -&amp;gt; link -&amp;gt; run的整个过程。理解了这些个之后，你就对那些从语言编程层面来说难于理解的问题自然领会了，比如：为什么C语言规范里会提到变量的作用域和生命周期？全局变量和局部变量的区别到底在哪？等等一些看起来是规定的东西，工科科学里一切不自然的概念都需要你用心去理解，去实践，达到自然的状态才有可能去解决实际遇到的问题，规则只是思想包袱，不会产生任何价值，大部分情况下会阻碍你解决问题。&lt;/p&gt;

&lt;h1 id=&quot;裸机程序的整体说明&quot;&gt;裸机程序的整体说明&lt;/h1&gt;

&lt;p&gt;我们都熟悉有操作系统支持的应用程序开发，比如 Linux下C语言的开发。我们可以不用关心程序启动的细节，同时我们一般还可以使用各种方便的lib 库，比如基本的IO操作(printf scan)，动态分配内存操作(malloc)，文件操作(fopen fwrite fread)等。有操作系统支持的情况下，程序的编译、链接、启动都是有操作系统支持的，常用的编程库函数使用的是标准的C库。&lt;/p&gt;

&lt;p&gt;那如果没有OS支持的情况下，想实现上面这些功能的话，该怎么做呐？这种情况就叫 Bare Metal (裸)程序开发。在嵌入式开发中是比较常见的情况，本blog 主要讲解基于Cortex-M3 的裸程序开发。本裸机程序实现了 基本IO，动态内存分配，基本函数库等功能。&lt;/p&gt;

&lt;h1 id=&quot;主程序main验证了那些功能&quot;&gt;主程序(main)验证了那些功能&lt;/h1&gt;

&lt;p&gt;主程序验证了基本的Startup，基本的IO功能，malloc功能，打印了全局变量和局部变量的地址(用于理解全局变量和局部变量的区别)。
其主程序代码如下：&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;stdlib.h&amp;gt;
#include &quot;diag/Trace.h&quot;
&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;local_test&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr_malloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  &lt;span class=&quot;n&quot;&gt;arr_malloc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;sizeof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr_malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
	  &lt;span class=&quot;n&quot;&gt;trace_puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;malloc error!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
	  &lt;span class=&quot;n&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;memcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr_malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;123456789&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;arr_malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;NULL&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Testing malloc &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;the string =%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr_malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Send a greeting to the trace device (skipped on Release).&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello ARM World by Linc Zhang!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// At this stage the system clock should have already been configured&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// at high speed.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;System clock: %u Hz&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;SystemCoreClock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;the [test]=0x%x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;the [local_test]=0x%x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;the address[test]=0x%x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;the address[local_test]=0x%x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;local_test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;the float type value temp =0x%f&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;timer_start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;blink_led_init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  
  &lt;span class=&quot;kt&quot;&gt;uint32_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;seconds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Infinite loop&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Infinite loop, never return.&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;如何实现的startup&quot;&gt;如何实现的startup&lt;/h1&gt;

&lt;p&gt;还是和有OS支持的情况下来对比，有OS的情况下分析一个Project，一般会从3个方面来进行分析：一是看源代码的组织形式；一是看Compile &amp;amp;&amp;amp; Link过程(即Makefile)；三是看Run时的情况(一般看运行起来后几个Process，几个Thread，以及他们之间的关系)。分析完这3个方面后，整个project从静到动，以及动静之间的转换都包括了，也就掌握了整个的Project。&lt;/p&gt;

&lt;p&gt;在没有OS的情况下，1 2 两个方面是一样的，只不过程序运行的基础环境不一样，裸机程序运行需要考虑的细节多一些。裸机程序需要考虑的基本问题有：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;编译生成的可执行程序结构是什么样的？整个可执行程序的入口在哪？&lt;/li&gt;
  &lt;li&gt;需要将可执行程序下载到什么地方？程序运行前需要做哪些准备工作？&lt;/li&gt;
  &lt;li&gt;C语言运行需要什么样的环境？&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;我们按照上面说的方法，从3各方面出发，分析我们的Project。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;源代码：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;顶层目录：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.
├── Debug
├── include
├── ldscripts
├── src
└── system
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;其中src目录是Application层的主逻辑代码，其中main.c就在src目录中，是业务逻辑层的主代码。
include目录是Application层的interface 说明文件。
system 目录是和启动有关系的代码。
ldscripts目录是link 脚本，主要告诉ld(链接器)如何链接各个Objects文件为可执行程序.
Debug目录是个编译目录，里面包含各种Makefile。&lt;/p&gt;

&lt;p&gt;更详细的项目目录结构：&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;.
├── Debug
│   ├── hello.elf
│   ├── hello.hex
│   ├── hello.map
│   ├── makefile
│   ├── objects.mk
│   ├── sources.mk
│   ├── src
│   │   ├── BlinkLed.d
│   │   ├── BlinkLed.o
│   │   ├── main.d
│   │   ├── main.o
│   │   ├── subdir.mk
│   │   ├── Timer.d
│   │   ├── Timer.o
│   │   ├── _write.d
│   │   └── _write.o
│   └── system
│       └── src
├── include
│   ├── BlinkLed.h
│   ├── stm32f10x_conf.h
│   └── Timer.h
├── ldscripts
│   ├── libs.ld
│   ├── mem.ld
│   └── sections.ld
├── src
│   ├── BlinkLed.c
│   ├── main.c
│   ├── Timer.c
│   └── _write.c
└── system
    ├── include
    │   ├── arm
    │   ├── cmsis
    │   ├── cortexm
    │   ├── diag
    │   └── stm32f1-stdperiph
    └── src
        ├── cmsis
        ├── cortexm
        ├── diag
        ├── newlib
        └── stm32f1-stdperiph
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;这里简单说明下system 目录，cmsis主要是soc相关的初始化代码，cortexm是Cortex-M3的启动相关代码，diag是使用Semihosting实现了基本的IO，newlib是newlib移植需要实现的函数，stm32f1-stdperiph 是soc片上的外设资源的Driver。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;编译&amp;amp;&amp;amp;链接:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;当然是直接 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;make&lt;/code&gt; 喽。&lt;/p&gt;

&lt;p&gt;编译的模板，自己根据实际文件名进行修改&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;arm-none-eabi-gcc &lt;span class=&quot;nt&quot;&gt;-mcpu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cortex-m3 &lt;span class=&quot;nt&quot;&gt;-mthumb&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Og&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fmessage-length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0 &lt;span class=&quot;nt&quot;&gt;-fsigned-char&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ffunction-sections&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fdata-sections&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ffreestanding&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fno-move-loop-invariants&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Wall&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Wextra&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-g3&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DDEBUG&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DUSE_FULL_ASSERT&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DTRACE&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DOS_USE_TRACE_SEMIHOSTING_DEBUG&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DSTM32F10X_MD&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DUSE_STDPERIPH_DRIVER&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-DHSE_VALUE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;8000000 &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../include&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../system/include&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../system/include/cmsis&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-I&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../system/include/stm32f1-stdperiph&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-std&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;gnu11
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;编译说明：编译单个文件其实还是挺简单，只是添加了一些功能性的宏定义。&lt;/p&gt;

&lt;p&gt;链接的模板，自己需要添加Objects文件&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;arm-none-eabi-g++ &lt;span class=&quot;nt&quot;&gt;-mcpu&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;cortex-m3 &lt;span class=&quot;nt&quot;&gt;-mthumb&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Og&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fmessage-length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0 &lt;span class=&quot;nt&quot;&gt;-fsigned-char&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ffunction-sections&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fdata-sections&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-ffreestanding&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fno-move-loop-invariants&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Wall&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Wextra&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g3&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; mem.ld &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; libs.ld &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; sections.ld &lt;span class=&quot;nt&quot;&gt;-nostartfiles&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-Xlinker&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--gc-sections&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-L&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;../ldscripts&quot;&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; _printf_float &lt;span class=&quot;nt&quot;&gt;-Wl&lt;/span&gt;,-Map,&lt;span class=&quot;s2&quot;&gt;&quot;hello.map&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--specs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;nano.specs &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;hello.elf&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;链接说明：链接时使用了-nostartfiles，含义是不使用Crt0.o 提供的启动代码，库函数还是使用arm-linux-gcc提供的new-lib。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;映像结构&amp;amp;&amp;amp;运行：&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;有操作系统的情况下，我们不需要关心可执行映像的具体结构，一个可执行程序文件从静态文件到动态运行这个过程叫Loader&amp;amp;&amp;amp;Run。这个过程是由OS来完成的，应用程序级别的开发是不需要关心这些细节的。对OS如何处理Link&amp;amp;&amp;amp;Loader这些细节感兴趣的，可以参考书籍：&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://book.douban.com/subject/3652388/&quot;&gt;程序员的自我修养&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://book.douban.com/subject/1436811/&quot;&gt;Linkers and Loaders&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;我们这里处理的是裸程序的启动细节问题，首先我们要知道的是通过编译器和链接器之后得到的二进制可执行映像的结构。也就是说得出的那个 *.bin 文件里面长啥样？一图胜万言，上张图先。
&lt;img src=&quot;/images/posts/2018-05-28-compile-link-loader-boot/code-data-segments.png&quot; alt=&quot;可执行映像的一般结构&quot; /&gt;&lt;/p&gt;

&lt;p&gt;我们大家都知道冯.诺依曼架构的计算机，它的基本思想是把“做事情的步骤和所需要的资源都提前编写好，然后让计算机自己根据需要读取操作步骤和资源，实现部分的计算自动化”。计算机的设计思想可谓是精妙的，实现真正的计算自动化也是很多科学家和工程师的夙愿。上面所说的做事情的步骤在计算机领域叫指令，所需要的资源在计算机领域叫数据。从计算机体系结构角度去看可执行映像的话，其实也就分为指令和数据两个大的部分。指令部分还是比较单一的，把各个源文件中的指令部分最后都汇聚到一起，形成所谓的text段。从功能上分，代码段只是需要CPU去读取，不需要修改，因为可以将其放在RO存储器里。数据这个部分从功能上来看，它必须支持读写，也即数据段执行时必须位于RW存储器里。从功能细节上分数据段又分为BSS段，Data段，Stack段，Heap段。从计算机体系结构角度来一一分析，从数据的生存周期角度来看，有的数据的生存周期和程序的生存周期是一致的(全局变量)，有的数据的生存周期是根据使用情况即时分配和释放的（局部变量、malloc动态分配的变量）。BSS段和Data段属于全生命周期的数据，在源程序里主要是那些在文件域定义的全局变量和使用static关键字定义的全生命周期变量，Data是那些在程序里定义变量时初始化为固定值的量，BSS段是那些在程序里定义变量时未初始化的变量，这些变量在映像真正执行前会自动初始化为0。对BSS段再多说一句，BSS段在映像文件里并不占用具体的空间，因为没有任何具体的信息，只需要在映像文件中提供BSS段的起始地址和大小信息即可。在映像文件实际执行前，把BSS段要求的Data区域在实际RAM中预留出来并把这些区域初始化为0。短生命周期的数据包括Heap和Stack，它们的特点是随用随申请，用完就释放，比较灵活。Heap是一段预留出来的大空间，可以根据需求随时申请和释放，就是我们常见的malloc free函数操作的空间就是Heap 空间，这部分空间在映像里是独立出来的一段空间，见上面的程序映像图。Stack也是独立预留出来的一段连续数据空间，它的作用还挺多，想更进一步了解的请看&lt;a href=&quot;http://www.bahutou.cn/2018/05/22/stack-using/&quot;&gt;Stack在函数调用、中断（异常）、RTOS中的应用&lt;/a&gt;。
从程序映像角度来看，就是代码段和根据功能划分的一些数据段组成的，使用映像资源最关键的就是要知道每条指令或者具体的变量在映像文件中的Offset。也就是我们常说的Address，我们在裸机环境下所说的Address就是真实的物理地址(Physical Address)。&lt;/p&gt;

&lt;p&gt;程序映像的事情说的差不多了，下面就得以STM32F103RBT6这种具体的Soc和arm-linux-gcc这种具体的compiler&amp;amp;&amp;amp;linker来进行详细说明。我们编译出来的映像的具体结构是什么样？整个可执行程序的入口在哪里？每个段的具体地址如何获取？可执行程序在执行前都做了哪些准备工作？下面我们来一一详细道来。
先来看看STM32F103RBT6这个soc的Memory map，还是来张图吧。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2018-05-28-compile-link-loader-boot/STM32F103RBT6_Memory map.png&quot; alt=&quot;Soc Memory map&quot; /&gt;&lt;/p&gt;

&lt;p&gt;我们看到RO存储Flash Memory的地址段是：0x08000000–0x0801FFFF 共128K。
RW存储SRAM的地址段是：0x20000000–0x20004FFF 共20K。
我们Soc的启动配置是从0x08000000地址开始启动。为节约RAM空间，我们启动时映像的代码段不搬运，直接读取Flash Memory，数据段需要可读写，因此需要将所有的数据段搬移到RAM中去。大致情况见下图：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2018-05-28-compile-link-loader-boot/load_and_exec_view.png&quot; alt=&quot;Load View&amp;amp;&amp;amp; Excute View&quot; /&gt;&lt;/p&gt;

&lt;p&gt;硬件情况就是这样，下面开始分析如何产生符合这款Soc的映像文件。下面一个重要的Tool出厂，link script，它控制着如何产生最终的映像文件。在分析具体的link script之前，先来说link script 里最重要的概念，Address &amp;amp;&amp;amp; Offset，前面也说了，到了映像文件格式这一层面，也就剩下各种连续的内容(段)和地址(Address)了，因此地址对映像来说是一个十分重要的资源。link script 无非就是告诉链接器哪段东西放在哪个地址上。那些段需要搬运，当然搬运也是需要地址的。&lt;/p&gt;

&lt;p&gt;来看看我们项目中用到的link script：
分连个层面来看，一是Memory Map相关的，一是段分配相关的。
先看Memory Map，&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-ld&quot;&gt;/*
 * Memory Spaces Definitions.
 *
 * Need modifying for a specific board. 
 *   FLASH.ORIGIN: starting address of flash
 *   FLASH.LENGTH: length of flash
 *   RAM.ORIGIN: starting address of RAM bank 0
 *   RAM.LENGTH: length of RAM bank 0
 *
 * The values below can be addressed in further linker scripts
 * using functions like 'ORIGIN(RAM)' or 'LENGTH(RAM)'.
 */

MEMORY
{
  RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K
  CCMRAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0
  FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K
  FLASHB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB0 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB1 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB2 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  EXTMEMB3 (rx) : ORIGIN = 0x00000000, LENGTH = 0
  MEMORY_ARRAY (xrw)  : ORIGIN = 0x00000000, LENGTH = 0
}

/*
 * For external ram use something like:

  RAM (xrw) : ORIGIN = 0x68000000, LENGTH = 20K

 */

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;定义了一个RO存储和一个RAM存储，地址空间和Soc硬件手册一致。&lt;/p&gt;

&lt;p&gt;再来看看各种段设置的情况，&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-ld&quot;&gt;/*
 * Default linker script for Cortex-M (it includes specifics for STM32F[34]xx).
 * 
 * To make use of the multi-region initialisations, define
 * OS_INCLUDE_STARTUP_INIT_MULTIPLE_RAM_SECTIONS for the _startup.c file.
 */

/*
 * The '__stack' definition is required by crt0, do not remove it.
 */
__stack = ORIGIN(RAM) + LENGTH(RAM);

_estack = __stack; 	/* STM specific definition */

/*
 * Default stack sizes.
 * These are used by the startup in order to allocate stacks 
 * for the different modes.
 */

__Main_Stack_Size = 1024 ;

PROVIDE ( _Main_Stack_Size = __Main_Stack_Size ) ;

__Main_Stack_Limit = __stack  - __Main_Stack_Size ;

/* &quot;PROVIDE&quot; allows to easily override these values from an 
 * object file or the command line. */
PROVIDE ( _Main_Stack_Limit = __Main_Stack_Limit ) ;

/*
 * There will be a link error if there is not this amount of 
 * RAM free at the end. 
 */
_Minimum_Stack_Size = 256 ;

/*
 * Default heap definitions.
 * The heap start immediately after the last statically allocated 
 * .sbss/.noinit section, and extends up to the main stack limit.
 */
PROVIDE ( _Heap_Begin = _end_noinit ) ;
PROVIDE ( _Heap_Limit = __stack - __Main_Stack_Size ) ;

/* 
 * The entry point is informative, for debuggers and simulators,
 * since the Cortex-M vector points to it anyway.
 */
ENTRY(_start)


/* Sections Definitions */

SECTIONS
{
    /*
     * For Cortex-M devices, the beginning of the startup code is stored in
     * the .isr_vector section, which goes to FLASH. 
     */
    .isr_vector : ALIGN(4)
    {
        FILL(0xFF)
        
        __vectors_start = ABSOLUTE(.) ;
        __vectors_start__ = ABSOLUTE(.) ; /* STM specific definition */
        KEEP(*(.isr_vector))     	/* Interrupt vectors */
        
		KEEP(*(.cfmconfig))			/* Freescale configuration words */   
		     
        /* 
         * This section is here for convenience, to store the
         * startup code at the beginning of the flash area, hoping that
         * this will increase the readability of the listing.
         */
        *(.after_vectors .after_vectors.*)	/* Startup code and ISR */

    } &amp;gt;FLASH

    .inits : ALIGN(4)
    {
        /* 
         * Memory regions initialisation arrays.
         *
         * Thee are two kinds of arrays for each RAM region, one for 
         * data and one for bss. Each is iterrated at startup and the   
         * region initialisation is performed.
         * 
         * The data array includes:
         * - from (LOADADDR())
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * The bss array includes:
         * - region_begin (ADDR())
         * - region_end (ADDR()+SIZEOF())
         *
         * WARNING: It is mandatory that the regions are word aligned, 
         * since the initialisation code works only on words.
         */
         
        __data_regions_array_start = .;
        
        LONG(LOADADDR(.data));
        LONG(ADDR(.data));
        LONG(ADDR(.data)+SIZEOF(.data));
        
        LONG(LOADADDR(.data_CCMRAM));
        LONG(ADDR(.data_CCMRAM));
        LONG(ADDR(.data_CCMRAM)+SIZEOF(.data_CCMRAM));
        
        __data_regions_array_end = .;
        
        __bss_regions_array_start = .;
        
        LONG(ADDR(.bss));
        LONG(ADDR(.bss)+SIZEOF(.bss));
        
        LONG(ADDR(.bss_CCMRAM));
        LONG(ADDR(.bss_CCMRAM)+SIZEOF(.bss_CCMRAM));
        
        __bss_regions_array_end = .;

        /* End of memory regions initialisation arrays. */
    
        /*
         * These are the old initialisation sections, intended to contain
         * naked code, with the prologue/epilogue added by crti.o/crtn.o
         * when linking with startup files. The standalone startup code
         * currently does not run these, better use the init arrays below.
         */
		KEEP(*(.init))
		KEEP(*(.fini))

		. = ALIGN(4);

		/*
         * The preinit code, i.e. an array of pointers to initialisation 
         * functions to be performed before constructors.
         */
		PROVIDE_HIDDEN (__preinit_array_start = .);
        
        /*
         * Used to run the SystemInit() before anything else.
         */
		KEEP(*(.preinit_array_sysinit .preinit_array_sysinit.*))
        
        /* 
         * Used for other platform inits.
         */
		KEEP(*(.preinit_array_platform .preinit_array_platform.*))
        
        /*
         * The application inits. If you need to enforce some order in 
         * execution, create new sections, as before.
         */
		KEEP(*(.preinit_array .preinit_array.*))

		PROVIDE_HIDDEN (__preinit_array_end = .);

		. = ALIGN(4);

		/*
         * The init code, i.e. an array of pointers to static constructors.
         */
		PROVIDE_HIDDEN (__init_array_start = .);
		KEEP(*(SORT(.init_array.*)))
		KEEP(*(.init_array))
		PROVIDE_HIDDEN (__init_array_end = .);

		. = ALIGN(4);

		/*
         * The fini code, i.e. an array of pointers to static destructors.
         */
		PROVIDE_HIDDEN (__fini_array_start = .);
		KEEP(*(SORT(.fini_array.*)))
		KEEP(*(.fini_array))
		PROVIDE_HIDDEN (__fini_array_end = .);

    } &amp;gt;FLASH

    /*
     * For some STRx devices, the beginning of the startup code
     * is stored in the .flashtext section, which goes to FLASH.
     */
    .flashtext : ALIGN(4)
    {
        *(.flashtext .flashtext.*)	/* Startup code */
    } &amp;gt;FLASH
 
    
    /*
     * The program code is stored in the .text section, 
     * which goes to FLASH.
     */
    .text : ALIGN(4)
    {
        *(.text .text.*)			/* all remaining code */
 
 		/* read-only data (constants) */
        *(.rodata .rodata.* .constdata .constdata.*) 		

        *(vtable)					/* C++ virtual tables */

		KEEP(*(.eh_frame*))

		/*
		 * Stub sections generated by the linker, to glue together 
		 * ARM and Thumb code. .glue_7 is used for ARM code calling 
		 * Thumb code, and .glue_7t is used for Thumb code calling 
		 * ARM code. Apparently always generated by the linker, for some
		 * architectures, so better leave them here.
		 */
        *(.glue_7)
        *(.glue_7t)

    } &amp;gt;FLASH

	/* ARM magic sections */
	.ARM.extab : ALIGN(4)
   	{
       *(.ARM.extab* .gnu.linkonce.armextab.*)
   	} &amp;gt; FLASH
   	
    . = ALIGN(4);
   	__exidx_start = .;   	
   	.ARM.exidx : ALIGN(4)
   	{
       *(.ARM.exidx* .gnu.linkonce.armexidx.*)
   	} &amp;gt; FLASH
   	__exidx_end = .;
   	
    . = ALIGN(4);
    _etext = .;
    __etext = .;
    
    /* MEMORY_ARRAY */
    /*
    .ROarraySection :
    {
     	*(.ROarraySection .ROarraySection.*)                          
    } &amp;gt;MEMORY_ARRAY
    */

	/*
	 * The secondary initialised data section.
	 */
    .data_CCMRAM : ALIGN(4)
    {
       FILL(0xFF)
       *(.data.CCMRAM .data.CCMRAM.*)
       . = ALIGN(4) ;
    } &amp;gt; CCMRAM AT&amp;gt;FLASH

	/* 
     * This address is used by the startup code to 
     * initialise the .data section.
     */
    _sidata = LOADADDR(.data);

    /*
     * The initialised data section.
     *
     * The program executes knowing that the data is in the RAM
     * but the loader puts the initial values in the FLASH (inidata).
     * It is one task of the startup to copy the initial values from 
     * FLASH to RAM.
     */
    .data : ALIGN(4)
    {
    	FILL(0xFF)
        /* This is used by the startup code to initialise the .data section */
        _sdata = . ;        	/* STM specific definition */
        __data_start__ = . ;
		*(.data_begin .data_begin.*)

		*(.data .data.*)
		
		*(.data_end .data_end.*)
	    . = ALIGN(4);

	    /* This is used by the startup code to initialise the .data section */
        _edata = . ;        	/* STM specific definition */
        __data_end__ = . ;

    } &amp;gt;RAM AT&amp;gt;FLASH
    
    /*
     * The uninitialised data sections. NOLOAD is used to avoid
     * the &quot;section `.bss' type changed to PROGBITS&quot; warning
     */
     
    /* The secondary uninitialised data section. */
	.bss_CCMRAM (NOLOAD) : ALIGN(4)
	{
		*(.bss.CCMRAM .bss.CCMRAM.*)
	} &amp;gt; CCMRAM

    /* The primary uninitialised data section. */
    .bss (NOLOAD) : ALIGN(4)
    {
        __bss_start__ = .;     	/* standard newlib definition */
        _sbss = .;              /* STM specific definition */
        *(.bss_begin .bss_begin.*)

        *(.bss .bss.*)
        *(COMMON)
        
        *(.bss_end .bss_end.*)
	    . = ALIGN(4);
        __bss_end__ = .;        /* standard newlib definition */
        _ebss = . ;             /* STM specific definition */
    } &amp;gt;RAM

    .noinit_CCMRAM (NOLOAD) : ALIGN(4)
    {
        *(.noinit.CCMRAM .noinit.CCMRAM.*)         
    } &amp;gt; CCMRAM
    
    .noinit (NOLOAD) : ALIGN(4)
    {
        _noinit = .;
        
        *(.noinit .noinit.*) 
        
         . = ALIGN(4) ;
        _end_noinit = .;   
    } &amp;gt; RAM
    
    /* Mandatory to be word aligned, _sbrk assumes this */
    PROVIDE ( end = _end_noinit ); /* was _ebss */
    PROVIDE ( _end = _end_noinit );
    PROVIDE ( __end = _end_noinit );
    PROVIDE ( __end__ = _end_noinit );
    
    /*
     * Used for validation only, do not allocate anything here!
     *
     * This is just to check that there is enough RAM left for the Main
     * stack. It should generate an error if it's full.
     */
    ._check_stack : ALIGN(4)
    {
        . = . + _Minimum_Stack_Size ;
    } &amp;gt;RAM
    
    /*
     * The FLASH Bank1.
     * The C or assembly source must explicitly place the code 
     * or data there using the &quot;section&quot; attribute.
     */
    .b1text : ALIGN(4)
    {
        *(.b1text)                   /* remaining code */
        *(.b1rodata)                 /* read-only data (constants) */
        *(.b1rodata.*)
    } &amp;gt;FLASHB1
    
    /*
     * The EXTMEM.
     * The C or assembly source must explicitly place the code or data there
     * using the &quot;section&quot; attribute.
     */

    /* EXTMEM Bank0 */
    .eb0text : ALIGN(4)
    {
        *(.eb0text)                   /* remaining code */
        *(.eb0rodata)                 /* read-only data (constants) */
        *(.eb0rodata.*)
    } &amp;gt;EXTMEMB0
    
    /* EXTMEM Bank1 */
    .eb1text : ALIGN(4)
    {
        *(.eb1text)                   /* remaining code */
        *(.eb1rodata)                 /* read-only data (constants) */
        *(.eb1rodata.*)
    } &amp;gt;EXTMEMB1
    
    /* EXTMEM Bank2 */
    .eb2text : ALIGN(4)
    {
        *(.eb2text)                   /* remaining code */
        *(.eb2rodata)                 /* read-only data (constants) */
        *(.eb2rodata.*)
    } &amp;gt;EXTMEMB2
    
    /* EXTMEM Bank0 */
    .eb3text : ALIGN(4)
    {
        *(.eb3text)                   /* remaining code */
        *(.eb3rodata)                 /* read-only data (constants) */
        *(.eb3rodata.*)
    } &amp;gt;EXTMEMB3
   

    /* After that there are only debugging sections. */
    
    /* This can remove the debugging information from the standard libraries */    
    /* 
    DISCARD :
    {
     libc.a ( * )
     libm.a ( * )
     libgcc.a ( * )
     }
     */
  
    /* Stabs debugging sections.  */
    .stab          0 : { *(.stab) }
    .stabstr       0 : { *(.stabstr) }
    .stab.excl     0 : { *(.stab.excl) }
    .stab.exclstr  0 : { *(.stab.exclstr) }
    .stab.index    0 : { *(.stab.index) }
    .stab.indexstr 0 : { *(.stab.indexstr) }
    .comment       0 : { *(.comment) }
    /*
     * DWARF debug sections.
     * Symbols in the DWARF debugging sections are relative to the beginning
     * of the section so we begin them at 0.  
     */
    /* DWARF 1 */
    .debug          0 : { *(.debug) }
    .line           0 : { *(.line) }
    /* GNU DWARF 1 extensions */
    .debug_srcinfo  0 : { *(.debug_srcinfo) }
    .debug_sfnames  0 : { *(.debug_sfnames) }
    /* DWARF 1.1 and DWARF 2 */
    .debug_aranges  0 : { *(.debug_aranges) }
    .debug_pubnames 0 : { *(.debug_pubnames) }
    /* DWARF 2 */
    .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
    .debug_abbrev   0 : { *(.debug_abbrev) }
    .debug_line     0 : { *(.debug_line) }
    .debug_frame    0 : { *(.debug_frame) }
    .debug_str      0 : { *(.debug_str) }
    .debug_loc      0 : { *(.debug_loc) }
    .debug_macinfo  0 : { *(.debug_macinfo) }
    /* SGI/MIPS DWARF 2 extensions */
    .debug_weaknames 0 : { *(.debug_weaknames) }
    .debug_funcnames 0 : { *(.debug_funcnames) }
    .debug_typenames 0 : { *(.debug_typenames) }
    .debug_varnames  0 : { *(.debug_varnames) }    
}


&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;链接脚本定义了上面提到的各种段，text、BSS、data、Stack、Heap等不同的段。定义了每个段在映像文件中的排布方式，定义了有哪些段需要在运行前从FLASH中搬运到RAM中。
我们拿出一个data段来进行说明。&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ld&quot;&gt;/*
     * The initialised data section.
     *
     * The program executes knowing that the data is in the RAM
     * but the loader puts the initial values in the FLASH (inidata).
     * It is one task of the startup to copy the initial values from 
     * FLASH to RAM.
     */
    .data : ALIGN(4)
    {
    	FILL(0xFF)
        /* This is used by the startup code to initialise the .data section */
        _sdata = . ;        	/* STM specific definition */
        __data_start__ = . ;
		*(.data_begin .data_begin.*)

		*(.data .data.*)
		
		*(.data_end .data_end.*)
	    . = ALIGN(4);

	    /* This is used by the startup code to initialise the .data section */
        _edata = . ;        	/* STM specific definition */
        __data_end__ = . ;

    } &amp;gt;RAM AT&amp;gt;FLASH
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;上面的脚本定义了一个段叫data，里面包含了所有Objects文件中的data段，不同文件中定义的全局变量和静态变量全部汇聚到了这一个段中。里面还定义了一些label，这些label其实就是映像文件中各个数据或者段的地址(Address/Offset)，主要用于给程序提供这些地址信息，让程序对映像文件中的这些资源进行处理。你像这个data段，需要在startup初始化阶段将data段从FLASH 复制到RAM中。既然要复制，那程序就需要知道源地址，目的地址以及要复制的长度。开始地址就是data段在整个映像的Offset地址，在这里起了个名字叫__data_start__ ，结束地址叫__data_end__ ，知道了开始地址和结束地址也就知道了信息源的所有信息(开始地址、结束地址、长度)。那目的地址在哪？别着急，目的地址的设置是使用了 &lt;strong&gt;AT&lt;/strong&gt; 这个指令，意思就是告诉链接器这段内容是需要搬运的，下载地址和运行地址是不一样的。&lt;/p&gt;
&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt;RAM AT&amp;gt;FLASH
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;上面的指令意思是这个段的实际链接地址是 RAM 这个Memory Region中定义的0x20000000开始的地方，根据内容依次往后放。但现在在映像中实际的位置是FLASH 这个Memory Region中定义的0x08000000开始的地方开始放置的，根据内容依次顺序放置的。在FLASH中这个内存域中，前面可能已经放置了启动代码和其他代码段。使用了这个说明后，产生的效果是在映像文件中是连续存放的内容(以0x08000000作为基地址)，但是data段实际的链接地址都是以0x20000000作为基地址的。比如你定义了一个全局变量 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int  A = 88;&lt;/code&gt;，它实际运行的地址在0x20000010这个地址，但是在最开始整个映像都在FLASH中，它可能在映像中的实际存在位置为0x08000100。在程序最开始(还没用到这个全局变量之前)的代码中需要将data段整体地从FLASH中移动到RAM中。如果不用&lt;strong&gt;AT&lt;/strong&gt; 指令的话，映像文件会直接按照链接地址生成，就意味着映像文件会很大，因为代码段0x08000000和数据段0x20000000之间有一个Gap，这个Gap需要使用大量的0来填充。想想都觉着这个映像很大。实际我们产生映像文件时是要同时考虑装载视图和运行视图这两个方面的。
本工程中搬运代码在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/src/newlib/_startup.c&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;__initialize_data&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
		   &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Iterate and copy word by word.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// It is assumed that the pointers are word aligned.&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;region_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Copy the DATA segment from Flash to RAM (inlined).&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;__initialize_data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_sidata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_sdata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_edata&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;看调用的函数  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;__initialize_data(&amp;amp;_sidata, &amp;amp;_sdata, &amp;amp;_edata);&lt;/code&gt;  咦，三个参数在哪里定义的？在链接脚本里。从调用也可以看出，链接脚本里定义的label就相当于地址，在C语言程序里要使用取地址符&lt;strong&gt;&amp;amp;&lt;/strong&gt;。去找找看：
其中_sdata 和 _edata这两个label是在 data数据段里定义的，作为目的地址存在，其范围在RAM Memory Region中定义的范围。
_sidata是在&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ld&quot;&gt;/* 
     * This address is used by the startup code to 
     * initialise the .data section.
     */
    _sidata = LOADADDR(.data);
	
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里定义的，是data数据段在映像中的Offset，其范围在FLASH Memory Region中定义的范围中。&lt;/p&gt;

&lt;p&gt;其他还有好多别的数据段，我就不一一分析了，也就data bss数据段需要启动时处理，是比较复杂的了。你像Stack和Heap段也只是分配空间，然后把起始地址，长度信息设置个label供程序使用罢了。链接脚本定义的各种label都是有用的，有的是给启动程序用的，有的是给库函数移植用的，有的是给调试器用的。&lt;/p&gt;

&lt;p&gt;说了这么多，整个程序的入口在哪里？有OS支持的情况下，一般主函数都是main，我们裸机开发，执行的第一条指令在哪？
看链接脚本&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ld&quot;&gt;/* 
 * The entry point is informative, for debuggers and simulators,
 * since the Cortex-M vector points to it anyway.
 */
ENTRY(_start)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;好像是叫 _start这个label，是个函数名称吗？先搜搜源代码看看。
还是在&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/src/newlib/_startup.c&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// This is the place where Cortex-M core will go immediately after reset,&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// via a call or jump from the Reset_Handler.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// For the call to work, and for the call to __initialize_hardware_early()&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// to work, the reset stack must point to a valid internal RAM area.&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__attribute__&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.after_vectors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noreturn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weak&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_start&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;CPU都有一个叫向量表的东西，就是规定了各种特殊情况下应该去执行哪里的代码。详细点说向量表包含 Interrupt 和 Exception两种类别。Cortex-M3也有自己的vectors。
&lt;img src=&quot;/images/posts/2018-05-28-compile-link-loader-boot/STM32x_vectors.png&quot; alt=&quot;STM32_Vectors&quot; /&gt;
上面只是列举了一部分Vectors。可以看到有一个reset vector handler，就是说系统刚上电启动或者复位时都会执行这个地址上的代码。我们代码中在这个位置提供了什么呐？&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// The vector table.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// This relies on the linker script to place at correct location in memory.&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.isr_vector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;used&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;pHandler&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__isr_vectors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Core Level - CM3&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_estack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// The initial stack pointer&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;Reset_Handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// The reset handler&lt;/span&gt;

      &lt;span class=&quot;n&quot;&gt;NMI_Handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// The NMI handler&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;HardFault_Handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// The hard fault handler&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到我们的reset handler放的是 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Reset_Handler&lt;/code&gt; 这个函数，看看这个函数干了些啥？&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__attribute__&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;section&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.after_vectors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;noreturn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Reset_Handler&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;_start&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;原来是直接调用的 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_start ()&lt;/code&gt; 函数。启动就是直接执行这个函数里的内容。
关于正常的CPU 初始化流程，网上一大堆，我们的大致流程是这样的：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;禁止终端、初始化Soc时钟频率、设置vectors位置等Soc相关初始化。&lt;/li&gt;
  &lt;li&gt;从FLASH搬运data数据段到RAM。&lt;/li&gt;
  &lt;li&gt;初始化bss段&lt;/li&gt;
  &lt;li&gt;进行其他Soc硬件平台资源配置。&lt;/li&gt;
  &lt;li&gt;处理main函数命令行参数(argc argv)。&lt;/li&gt;
  &lt;li&gt;初始化C++运行环境，比如：静态类的构造函数。&lt;/li&gt;
  &lt;li&gt;调用main函数。&lt;/li&gt;
  &lt;li&gt;C++ 退出执行环境的一些扫尾工作，比如：静态类的析构函数。&lt;/li&gt;
  &lt;li&gt;程序中调用exit函数的具体实现工作，实现了_exit。&lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;使用arm-linux-gcc-带的newlib得自己实现那些函数&quot;&gt;使用arm-linux-gcc 带的newlib得自己实现那些函数&lt;/h1&gt;

&lt;p&gt;前面的分析过程中其实已经涉及到一些newlib库的函数，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/src/newlib/_startup.c&lt;/code&gt; 中涉及到一些和启动有关系的代码：包括数据段的搬移、bss段的初始化、C++运行环境的初始化等。除了这些初始化相关的功能外，newlib还需要实现那些功能？程序的退出设计(exit)、Heap管理功能实现、标准常用库函数syscall实现(open read write close等)。我们一个个来说下，程序的exit函数，需要调用底层的库函数_exit(),我们这里实现的_exit非常简单。&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// On Release, call the hardware reset procedure.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// On Debug we just enter an infinite loop, to be used as landmark when halting&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// the debugger.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// It can be redefined in the application, if more functionality&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// is required.&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;weak&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_exit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unused&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if !defined(DEBUG)
&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;__reset_hardware&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// TODO: write on trace&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以在程序退出时打印一些Debug信息。我们这里退出main函数之后，直接进入了死循环。&lt;/p&gt;

&lt;p&gt;下面聊一聊Heap管理，主要需要实现 _sbrk 这个函数。实现这个函数的文件是： &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/src/newlib/_sbrk.c&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;n&quot;&gt;caddr_t&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;_sbrk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;incr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Heap_Begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Defined by the linker.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;extern&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_Heap_Limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Defined by the linker.&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_heap_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_block_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_heap_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;current_heap_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Heap_Begin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;current_block_address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_heap_end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Need to align heap to word boundary, else will get&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// hard faults on Cortex-M0. So we assume that heap starts on&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// word boundary, hence make sure we always add a multiple of&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// 4 to it.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;incr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;incr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// align value to 4&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_heap_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;incr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_Heap_Limit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// Some of the libstdc++-v3 tests rely upon detecting&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// out of memory errors, so do not abort here.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#if 0
      extern void abort (void);

      _write (1, &quot;_sbrk: Heap and stack collision\n&quot;, 32);

      abort ();
#else&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// Heap has overflowed&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;errno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ENOMEM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;caddr_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;current_heap_end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;incr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;caddr_t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_block_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们平常使用的malloc，free等库函数，到最终都会调用_sbrk()这个函数。关于这个函数的处理流程这里不再分析，简单提一下这个Heap的起始地址和长度信息也是通过链接脚本定义的，_Heap_Begin和_Heap_Limit。
syscall的实现在 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/src/newlib/_syscalls.c&lt;/code&gt;
基本的syscall，这里都实现为了Semihosting方式。&lt;/p&gt;

&lt;h1 id=&quot;怎么利用semihosting-实现的基本io&quot;&gt;怎么利用Semihosting 实现的基本IO&lt;/h1&gt;

&lt;p&gt;本项目中，基本的IO都使用Semihosting实现。打印功能，使用自己实现的trace_printf函数，没有使用newlib库的printf函数。newlib中的printf函数开销比较大，我们这个只是调试的时候需要简单的输出功能。因此，自己实现了一个简单的利用Semihosting做的打印输出功能。
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/src/diag/Trace.c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;实现了以下接口：&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;trace_printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...);&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;trace_puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;trace_putchar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;trace_printf底层会调用 Semihosting的实现函数 trace_write，&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/src/diag/trace_impl.c&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;trace_write&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unused&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)),&lt;/span&gt;
	     &lt;span class=&quot;kt&quot;&gt;size_t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nbyte&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__attribute__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unused&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if defined(OS_USE_TRACE_ITM)
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_trace_write_itm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#elif defined(OS_USE_TRACE_SEMIHOSTING_STDOUT)
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_trace_write_semihosting_stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#elif defined(OS_USE_TRACE_SEMIHOSTING_DEBUG)
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_trace_write_semihosting_debug&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nbyte&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们在编译时使用了OS_USE_TRACE_SEMIHOSTING_DEBUG 宏定义，因此会调用_trace_write_semihosting_debug函数，这个函数调用call_host实现了Semihosting的输出到Host主机的功能。&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bare_metal_hello_world/system/include/arm/semihosting.h&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;inline&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;__attribute__&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;always_inline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;call_host&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;asm&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;volatile&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;

      &lt;span class=&quot;s&quot;&gt;&quot; mov r0, %[rsn]  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;s&quot;&gt;&quot; mov r1, %[arg]  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#if defined(OS_DEBUG_SEMIHOSTING_FAULTS)
&lt;/span&gt;      &lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AngelSWITestFault&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#else
&lt;/span&gt;      &lt;span class=&quot;s&quot;&gt;&quot; &quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;AngelSWIInsn&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot; %[swi] &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;#endif
&lt;/span&gt;      &lt;span class=&quot;s&quot;&gt;&quot; mov %[val], r0&quot;&lt;/span&gt;

      &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;=r&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* Outputs */&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rsn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;swi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;i&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AngelSWI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* Inputs */&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;r3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;ip&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;lr&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;memory&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;cc&quot;&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// Clobbers r0 and r1, and lr if in supervisor mode&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;// Accordingly to page 13-77 of ARM DUI 0040D other registers&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// can also be clobbered. Some memory positions may also be&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// changed by a system call, so they should not be kept in&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// registers. Note: we are assuming the manual is right and&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Angel is respecting the APCS.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;如何利用-qemu-实现模拟运行调试&quot;&gt;如何利用 QEMU 实现模拟运行、调试&lt;/h1&gt;
&lt;p&gt;调试环境的使用，在&lt;a href=&quot;http://www.bahutou.cn/2018/05/09/demo-using-the-env/&quot;&gt;基于Docker环境开发、调试嵌入式软件（Embedded Software develop/Debug using Docker）&lt;/a&gt;有详细的说明。&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/home/work/   zhanglianpin/ucos_debug_env  qemu-system-gnuarmeclipse  &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--nographic&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;--board&lt;/span&gt; STM32-P103 &lt;span class=&quot;nt&quot;&gt;--image&lt;/span&gt; hello.elf   &lt;span class=&quot;nt&quot;&gt;--gdb&lt;/span&gt; tcp::1234
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;输出：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GNU ARM Eclipse 64-bits QEMU v2.8.0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;qemu-system-gnuarmeclipse&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Board: &lt;span class=&quot;s1&quot;&gt;'STM32-P103'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Olimex Prototype Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F103RBT6&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Device file: &lt;span class=&quot;s1&quot;&gt;'/opt/gnuarmeclipse/qemu/2.8.0-201703022210-head/share/qemu/devices/STM32F103xx-qemu.json'&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Device: &lt;span class=&quot;s1&quot;&gt;'STM32F103RB'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Cortex-M3 r0p1, MPU, 4 NVIC prio bits, 43 IRQs&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, Flash: 128 kB, RAM: 20 kB.
Image: &lt;span class=&quot;s1&quot;&gt;'hello.elf'&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Command line: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;none&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Load  14960 bytes at 0x08000000-0x08003A6F.
Load    504 bytes at 0x08003A70-0x08003C67.
Load    416 bytes at 0x200001F8-0x20000397.
Cortex-M3 r0p1 core initialised.
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/RCC'&lt;/span&gt;, address: 0x40021000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/FLASH'&lt;/span&gt;, address: 0x40022000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/PWR'&lt;/span&gt;, address: 0x40007000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/AFIO'&lt;/span&gt;, address: 0x40010000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/EXTI'&lt;/span&gt;, address: 0x40010400, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOA'&lt;/span&gt;, address: 0x40010800, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOB'&lt;/span&gt;, address: 0x40010C00, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOC'&lt;/span&gt;, address: 0x40011000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOD'&lt;/span&gt;, address: 0x40011400, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOE'&lt;/span&gt;, address: 0x40011800, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/peripheral/led:red'&lt;/span&gt; 12&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;10 @&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;331,362&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; active low &lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOC'&lt;/span&gt;,12
QEMU 2.8.0 monitor - &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'help'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;more information
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;qemu&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Cortex-M3 r0p1 core reset.

Testing malloc 
the string &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;123456789
Hello ARM World by Linc Zhang!
System clock: 72000000 Hz
the &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]=&lt;/span&gt;0xa
the &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;local_test]&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0x8
the address[test]&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0x20000020
the address[local_test]&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0x20004fd4
the float &lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;value temp &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0x0.010000
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;led:red off]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;可以看到我们验证了malloc函数，可以正常工作。我们顺便验证了下全局变量和局部变量在RAM中的实际地址，test定义的是个Global的变量，可以看到地址是0x20000020，确实是在RAM Region定义的范围，地址确实是从0x20000000 开始用的。函数内的局部变量使用的是Stack的内存空间，从上面介绍的内容来看，Stack是从RAM高地址向低地址使用的，这里RAM最高地址是0x20004fff，我们local_test变量的地址是0x20004fd4，和预期情况一致。我们也测试了浮点数的打印，newlib本身没有启用浮点数的支持，要想使用浮点数的输入、输出功能，需要使用编译器链接选项 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-u _printf_float&lt;/code&gt; 强制链接相关库函数。&lt;/p&gt;

&lt;h1 id=&quot;感谢&quot;&gt;感谢&lt;/h1&gt;

&lt;p&gt;本blog 中使用的源代码是来源于项目&lt;a href=&quot;https://gnu-mcu-eclipse.github.io/&quot;&gt;GNU MCU Eclipse&lt;/a&gt;的 C project工程模块，使用Eclipse创建一个基本的Cortex-M3 裸机程序的步骤见：&lt;a href=&quot;https://gnu-mcu-eclipse.github.io/tutorials/blinky-arm/&quot;&gt;Tutorial: Create a Blinky ARM test project&lt;/a&gt;。本blog只是按照自己的理解，分析了一下几个关键点和整体流程。项目作者是&lt;a href=&quot;ilg@livius.net&quot;&gt;Liviu Ionescu&lt;/a&gt;. 他的另一个项目是&lt;a href=&quot;https://github.com/micro-os-plus/micro-os-plus-iii&quot;&gt;micro-os-plus-iii&lt;/a&gt;,一个嵌入式软件开发基础套件，支持C api C++ api。感谢Liviu Ionescu。&lt;/p&gt;

&lt;h1 id=&quot;引用资源&quot;&gt;引用资源&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/zhanglianpin/bare_metal_hello_world&quot;&gt;Project source code&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content><author><name>Linc Zhang</name></author><summary type="html">本篇文章以STM32为硬件平台，使用GNU GCC作为开发工具，详细分析Compile 、Link 、Loader的过程以及Image(二进制程序)启动的详细分析。整个过程分析涉及到RW可读写段从Flash到Mem的Copy，BSS段的初始化，Stack和Heap的初始化，C库函数移植、利用Semihosting 实现基本的IO等内容。基本可以让你从更深刻的层面理解Source -&amp;gt; Compile -&amp;gt; link -&amp;gt; run的整个过程。理解了这些个之后，你就对那些从语言编程层面来说难于理解的问题自然领会了，比如：为什么C语言规范里会提到变量的作用域和生命周期？全局变量和局部变量的区别到底在哪？等等一些看起来是规定的东西，工科科学里一切不自然的概念都需要你用心去理解，去实践，达到自然的状态才有可能去解决实际遇到的问题，规则只是思想包袱，不会产生任何价值，大部分情况下会阻碍你解决问题。</summary></entry><entry><title type="html">Stack在函数调用、中断（异常）、RTOS中的应用</title><link href="https://www.bahutou.cn/2018/05/22/stack-using/" rel="alternate" type="text/html" title="Stack在函数调用、中断（异常）、RTOS中的应用" /><published>2018-05-22T00:00:00+08:00</published><updated>2018-05-22T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/05/22/stack-using</id><content type="html" xml:base="https://www.bahutou.cn/2018/05/22/stack-using/">&lt;p&gt;在计算机程序中，分支[Branch]具有很重要的意义。函数调用、中断产生时程序的跳转、OS中的Multiple Task的切换等等这些均属于分支范畴，说的直白点就是根据需求合理的控制执行流。执行这些跳转共有一个特征：还需要再返回到跳转前的Point。怎么记录需要返回到哪里？多层级的调用和返回都是有顺序的，怎么保证这些顺序？跳转前如有执行的环境怎么原封不动地保存？这样返回时才能继续之前的工作。程序执行的环境或者说执行流从CPU层次来看主要包括哪些核心内容？本篇文章重点介绍这些内容。&lt;/p&gt;

&lt;h3 id=&quot;何为stack&quot;&gt;何为Stack？&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29&quot;&gt;Stack&lt;/a&gt;是这样一种结构:本身是一段连续的内存空间，那怎么使用这样一种内存空间才算是起到了栈的实际作用呐？首先要规定这一段连续空间的基地址，然后就从这个基地址开始依次放东西。取东西时也是从最上面的开始取。Stack这个英文含义就是把东西堆叠起来的意思。就像水桶盛水一样，进水的时候是从低往上，放水的时候是从上往低。&lt;strong&gt;存取有一定的先后顺序.&lt;/strong&gt; 按照上面的方案管理这一段存储空间，就是发挥了栈的作用。因为栈使用的频率实在是太高了，所以在计算机汇编层次就有专门操作栈的指令。包括Push（入栈）、Pop（出栈）等。&lt;/p&gt;

&lt;p&gt;其实栈又有一些逻辑上的分类：&lt;/p&gt;

&lt;p&gt;根据先腾出空间再用还是先用再腾空间分为：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;满堆栈：即入栈后堆栈指针sp指向最后一个入栈的元素。也就是sp先减一（加一）再入栈。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;空堆栈：即入栈后堆栈指针指向最后一个入栈元素的下一个元素。也就是先入栈sp再减一（或加一）。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;根据从高地址开始用还是从低地址开始用分为：&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;递增堆栈：即堆栈一开始的地址是低地址，向高地址开始递增。就如同一个水杯（假设上面地址大）开口的是大地址，从杯底开始装水。自己画一画图就清楚了。我就偷懒一下不画了。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;递减堆栈：即堆栈一开始的地址是高地址，向低地址开始递增。就如同还是刚才说的那个水杯，现在开口的是小地址，从大地址开始用，往下走，相当于杯子口朝下。我们用的时候是把水往上一点点压上去。呵呵呵，不过这样的杯子就失去了用途。但在内存上还是可以的。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;那么根据这上面分类方法，我们就可以得到四种栈的类型。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cortex-M3中使用的是递减满堆栈(full descending stack)。&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&quot;stack在函数调用时的应用&quot;&gt;Stack在函数调用时的应用&lt;/h3&gt;

&lt;p&gt;我们使用高级语言设计程序时，为了程序的简介性和易读性，使用合理的函数抽象和函数调用是比较常用的设计方法。在函数调用时，有两个核心的问题需要关注：&lt;strong&gt;指令流(PC)的控制、临时数据(FP)的保存和恢复&lt;/strong&gt;。这个也好理解，数据结构里提到的程序=数据结构+算法也是一个意思，一个程序就有两个重要的内容：指令、数据。通俗地描述一下函数调用时需要考虑的问题，大家想一想，我们写c语言时用到函数调用，有时候还嵌套调用很多函数。还有有些函数还需要参数和返回值。怎么处理各个函数的参数和返回值，以及当每一个函数完成工作时该返回到那个地方。这些都是要解决的问题。当然最容易想到的也是必须做的是在进行调用跳转之前，把我这个函数现有的状态保存起来，保存什么那，调用函数返回后的下一条指令，还有我这个函数需要的哪些数据。还有就是保存这些信息到哪些地方哪？这些都是我们要解决的问题。还有就是你不光要保存这些信息，还要保存这些信息的顺序。因为函数调用本身有顺序，你像a调用b，b又接着调用c。在c执行完后要返回到b，b执行完再返回a。呵呵，有顺序。&lt;/p&gt;

&lt;p&gt;我们一一想办法来解决，当然别人已经用栈的策略解决的很完美了，我们只是想一些更简洁的最容易想起来的但是不完善的方法，也正说明了人家的策略是多么的优秀。&lt;/p&gt;

&lt;p&gt;关于调用函数的问题，我们可以把返回地址保存到一些地方，当然程序员知道在那？还知道顺序，再根据顺序返回就好了，但做这样的工作太累了，除了写程序还要记这些东西。这样太累了，聪明的程序员肯定也不这样做。关于传参，有这样可以考虑的，用专门规定好的寄存器来做传参。行，但有缺陷,如果传的参数很多或者是变化的，就不好用寄存器传参了。而且我们有操作系统时往往要求编译器产生的代码具有可重入性，也就是保证代码和数据的相对独立性。一个函数被调用两次，都有两次的参数环境。到底现在我们是怎么做的呐。答案是用栈。&lt;/p&gt;

&lt;p&gt;其他废话不多说了，直接上个Cortex-M3的Demo。&lt;/p&gt;

&lt;p&gt;function_stack.c ：&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;  &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;


&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;  &lt;span class=&quot;nf&quot;&gt;main_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;



&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;  &lt;span class=&quot;nf&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result_temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;n&quot;&gt;result_temp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result_temp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;33&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;


&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;function_stack.s  :&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cpu&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arm7tdmi&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eabi_attribute&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;   &lt;span class=&quot;s&quot;&gt;&quot;function_stack.c&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;align&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main_frame&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unified&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arm&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fpu&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;softvfp&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;main_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;main_frame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;supports&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interworking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pretend&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame_needed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uses_anonymous_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;push&lt;/span&gt;    &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bl&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;nop&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;needed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;pop&lt;/span&gt;     &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bx&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;main_frame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main_frame&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;align&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unified&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arm&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fpu&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;softvfp&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;supports&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interworking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pretend&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame_needed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uses_anonymous_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;push&lt;/span&gt;    &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bl&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;needed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;pop&lt;/span&gt;     &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bx&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;align&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kr&quot;&gt;global&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unified&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arm&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fpu&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;softvfp&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;supports&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;interworking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pretend&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame_needed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;uses_anonymous_args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;eliminated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]!&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;33&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;nop&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;needed&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[sp],&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;bx&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;size&lt;/span&gt;   &lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;test&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ident&lt;/span&gt;  &lt;span class=&quot;s&quot;&gt;&quot;GCC: (GNU Tools for Arm Embedded Processors 7-2017-q4-major) 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204]&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;先用gdb直观的感觉一下function stack。
在函数test处打个Break。&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;gdb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; bt
&lt;span class=&quot;c&quot;&gt;#0  0x0800023c in test () at main.c:48&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#1  0x0800022a in add (a=1, b=2) at main.c:42&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#2  0x080001e2 in main () at main.c:29&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;gdb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; frame 0
&lt;span class=&quot;c&quot;&gt;#0  0x0800023c in test () at main.c:48&lt;/span&gt;
48              int a &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 31,b &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 32,c &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 33&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;再来张图直观感受下，DrawSquare调用DrawLine。&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2018-05-22-stack-using/call_stack.png&quot; alt=&quot;Call stack&quot; title=&quot;Call stack Frame&quot; /&gt;&lt;/p&gt;

&lt;p&gt;下面我们好好分析一下函数调用的函数帧。
整个函数栈帧  main—add—test 。
下面详细分析下main函数调用add函数，然后add函数调用test的整个过程，分析下Stack在其中的作用。
main函数在调用add时，有两方面的工作需要做：保存main函数的当前数据状态(核心Registers)、传递的参数、返回参数和test函数执行完毕后的返回地址等相关的执行流。我们看编译器编译出来的汇编代码，控制data相关的Registers是：FP、SP ;控制指令流的Registers为PC、LR。一个基本原则是如果函数调用发生后，子函数需要改变的那些个Registers都需要保存到Stack中。&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;push&lt;/span&gt;	&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;我们知道add函数会使用FP来操作add函数内部的data registers，而add函数里面又调用了test函数，从而改变了LR的值，因此需要将FP和LR保存到main函数栈帧中。这样当add函数执行完返回时，弹出原来保存的FP、LR就可以恢复到原来main函数时的状态。下面是调整FP的指针值，使其指向Stack中FP的位置。以后在main函数栈帧里操作数据都使用FP这个指针，以这个为基础操作Stack。接下来就要分配main函数需要的局部变量了，包括main函数里自己申请的局部变量result，以及其他需要传递给add函数的参数。我们看到我们将result的值11放到了R3中，然后存到了main的栈帧中，原因是因为main函数里需要使用这个R3，但子函数add中也有可能使用R3这个Register，因此需要将R3保存到main函数的栈帧中，到时候从add函数返回时可以恢复到未调用add函数之前的main函数状态。&lt;/p&gt;

&lt;p&gt;后面就开始给add函数传递参数了。&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;可以看到使用的是R0和R1寄存器来传递1 和 2 这两个参数。这个是要参考AAPCS的，这个规范里就是这么规定的。&lt;/p&gt;

&lt;p&gt;下面直接执行bl 指令用于跳转。&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;bl&lt;/span&gt;	&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;没事，别担心，我们已经把main函数相关的内容都保存起来了，不怕add函数破坏，破坏了我可以再恢复。^_^。
bl指令修改了两个Registers的值，PC和LR。&lt;/p&gt;

&lt;p&gt;下面开始到了add的地盘，&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;k&quot;&gt;push&lt;/span&gt;	&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;老套路，因为后面add函数会调用test函数，所以先把核心的FP LR保存起来，调整FP指针。add函数用到了R0,R1这两个Registers，而后面又要调用test函数，因此要把R0，R1这两个Registers保存起来。后面还有一个result_temp的值为22，也需要保存起来。后面执行了具体的加法操作。把结果存到了R3中。然后执行bl指令，跳转到test函数。&lt;/p&gt;

&lt;p&gt;test函数里面和main、add函数栈帧也基本一致，只不过test没有要调用的子函数了，不会修改LR指针，因此不需要保存LR了。其他的倒是没什么特别的地方。&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]!&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;33&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;str&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;nop&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;needed&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[sp],&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;bx&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;调用正向过程分析完了，我们接着分析一下Return过程。重点分析add返回到main的情况。&lt;/p&gt;
&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;	&lt;span class=&quot;n&quot;&gt;ldr&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r3&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;sub&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
	&lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;needed&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;pop&lt;/span&gt;	&lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;bx&lt;/span&gt;	&lt;span class=&quot;n&quot;&gt;lr&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;add函数需要把结果返回到main函数中，使用当前栈帧的FP将add的返回值load到R3中，然后放到R0中，最后根据FP调整SP，最后把弹出刚进到add函数时保存到FP,LR的值从Stack中弹出来。这样LR的值就是add函数执行结束后，需要返回的值，FP就是main函数的栈帧FP指针。R0中保存的是add函数的返回值，当然也是AAPCS规定的喽。执行bx之后，一切后回到了main函数栈帧。&lt;/p&gt;

&lt;p&gt;分析完了，这里面有两个链表结构：一个PC和LR组成的指令流链表；一个SP和FP组成的数据流链表。以FP作为例子，FP始终指向当前Stack存放上一个FP的栈地址上，操作这个FP可以读取到当前栈帧的Data，当前函数返回后，将FP指向的Stack里存的上一个FP的值放到FP中，就保证了FP永远指向当前函数的栈帧。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Call Stack 最好是自己动手画画动态的栈帧变化，你就理解什么叫Call Frame了，也顺便理解了什么是Local Variable了.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;同时，从上面的分析我们也可以看到，从CPU角度来看，一个执行流的核心资源就是一些Registers再加上一些逻辑运算和Mem的操作&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;对计算机描述比较清楚的一本书是&lt;a href=&quot;https://eleccompengineering.files.wordpress.com/2014/07/structured_computer_organization_5th_edition_801_pages_2007_.pdf&quot;&gt;Structured Computer Organization(Andrew S.Tanenbaum)&lt;/a&gt; 欢迎阅读这本书。&lt;/p&gt;

&lt;p&gt;要想系统的了解汇编语言级别的函数调用规范和二进制规范还请参考以下规范：&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;AADWARF&lt;/strong&gt;  DWARF for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;AAELF&lt;/strong&gt;    ELF for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;AAPCS&lt;/strong&gt;    Procedure Call Standard for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;ADDENDA&lt;/strong&gt;  Addenda to, and errata in, the ABI for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;BPABI&lt;/strong&gt;    Base Platform ABI for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;BSABI&lt;/strong&gt;    This document ABI for the ARM Architecture (Base Standard)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CLIBABI&lt;/strong&gt;  C Library ABI for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CPPABI&lt;/strong&gt;   C++ ABI for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;EHABI&lt;/strong&gt;    Exception Handling ABI for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;EHEGI&lt;/strong&gt;    Exception handling components, example implementations&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;RTABI&lt;/strong&gt;    Run-time ABI for the ARM Architecture&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://mentorembedded.github.com/cxxabi/abi.html&quot;&gt;&lt;strong&gt;GC++ABI&lt;/strong&gt;&lt;/a&gt; Generic C++ ABI&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://dwarfstd.org/Dwarf3Std.php&quot;&gt;&lt;strong&gt;GDWARF&lt;/strong&gt;&lt;/a&gt; DWARF 3.0, the generic debug format.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.sco.com/developers/gabi/&quot;&gt;&lt;strong&gt;GABI&lt;/strong&gt;&lt;/a&gt;  Generic ELF, 17th December 2003 draft.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.linuxbase.org/spec/refspecs/&quot;&gt;&lt;strong&gt;GLSB&lt;/strong&gt;&lt;/a&gt;  gLSB v1.2 Linux Standard Base&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.openbsd.org/&quot;&gt;&lt;strong&gt;Open BSD&lt;/strong&gt;&lt;/a&gt; Open BSD standard&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;stack在中断或者异常发生时的应用&quot;&gt;Stack在中断或者异常发生时的应用&lt;/h3&gt;

&lt;p&gt;我们以STM32F103(Cortex-M3)为例，具体说明下中断或者异常发生时Stack的作用。
前面说了，只要有Branch的产生，就需要保存跳转之前的一些运行状态。正常情况下，Cortex-M3会在Thread Mode运行一个执行流。当有外部中断或者CPU异常发生时，会切换到Handle Mode，且需要使用Stack保存一些当前状态，以保证中断/异常服务程序返回时，能继续被打断的工作。&lt;/p&gt;

&lt;p&gt;具体这些内容请参见
&lt;a href=&quot;http://www.st.com/content/ccc/resource/technical/document/programming_manual/5b/ca/8d/83/56/7f/40/08/CD00228163.pdf/files/CD00228163.pdf/jcr:content/translations/en.CD00228163.pdf&quot;&gt;STM32 Programming manual&lt;/a&gt; 的2.3 章节Exception model 和 &lt;a href=&quot;http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/DUI0552A_cortex_m3_dgug.pdf&quot;&gt;Cortex-M3 Devices Generic User Guide&lt;/a&gt; 的2.3章节的内容。&lt;/p&gt;

&lt;p&gt;这里仅仅简单介绍一下大致流程，当中断或者异常发生时，硬件会自动保存部分关键Registers到当前使用的Stack中。当然，其他寄存器需要软件保存到Stack。然后将一个特殊的Return Value(0xFFFFFFFx) 放到LR寄存器中，当中断/异常服务程序返回时，CPU通过判断这个特殊的返回值得知这是一个中断或者异常跳转，然后硬件自动将之前保存的关键Registers弹出来以恢复Thread的运行。这里有一些细节，RTOS用到的一些硬件特性会有一个专门的文章介绍。&lt;/p&gt;

&lt;h3 id=&quot;stack在rtos中的应用&quot;&gt;Stack在RTOS中的应用&lt;/h3&gt;

&lt;p&gt;前面说了，Cortex-M3这个CPU默认的执行流只有两个，一个是Thread Mode下的执行流，一个是当中断或者异常发生时产生的Handle Mode下的执行流。RTOS提供的一个核心服务是抽象出更多的执行流，也叫Task。关于为什么要抽象出更多的执行流，前面文章里也给出了明确的说明。这个核心控制器一般CPU是单core的，只能提供一个执行流，再加上Interrupt，可以说整体就有了两个可管理的执行流，且中断的执行流优先级要大于CPU提供的执行流。&lt;/p&gt;

&lt;p&gt;如果利用软件管理手段能把CPU上的执行流管理起来，势必能加速整体的吞吐量和实时响应能力。因为CPU上的执行流从宏观上来看利用CPU进行运算的时间是间隔的，这个也很好理解，因为CPU运算能力是很强的，但是一个任务一般会涉及到等待外部事件，外部事件发生后才去做逻辑处理或者数值运算。在等待外部相对于CPU运算来说慢的多的多的事件时，如果能把CPU让给其他任务来用，那CPU的整体利用率就很高了。真是不错的想法。一个嵌入式产品不可能不与外部交互，毕竟科技产品是为人服务的。这样一个执行流在等待一些慢的事件时，可以把CPU让出来让其他Task使用，这样整个CPU利用率就提高了，系统整体响应就快了。&lt;/p&gt;

&lt;p&gt;切换Task对CPU来讲，就是保存当前Task的一些核心的Registers状态，然后Load要切换的Task原先保存好的各个寄存器。就实现了Task切换。每个Task都有自己独立的Stack，保存了当前CPU所有的Registers。
来张图：
&lt;img src=&quot;/images/posts/2018-05-22-stack-using/RTOS_stack.png&quot; alt=&quot;Call stack&quot; title=&quot;RTOS stack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;你看，每一个Task都有一个独立的Stack，用于保存自身的运行状态。&lt;/p&gt;

&lt;h3 id=&quot;引用资源&quot;&gt;引用资源&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://blog.csdn.net/zhanglianpin/article/details/7334451&quot;&gt;C语言和堆栈&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://infocenter.arm.com/help/topic/com.arm.doc.espc0002/ATPCS.pdf&quot;&gt;AAPCS: The ARM-THUMB Procedure Call Standard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://infocenter.arm.com/help/topic/com.arm.doc.ihi0036b/IHI0036B_bsabi.pdf&quot;&gt;BSABI: ABI for the ARM Architecture (Base Standard)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.st.com/content/ccc/resource/technical/document/programming_manual/5b/ca/8d/83/56/7f/40/08/CD00228163.pdf/files/CD00228163.pdf/jcr:content/translations/en.CD00228163.pdf&quot;&gt;STM32 Programming manual&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/DUI0552A_cortex_m3_dgug.pdf&quot;&gt;Cortex-M3 Devices Generic User Guide&lt;/a&gt;&lt;/p&gt;</content><author><name>Linc Zhang</name></author><summary type="html">在计算机程序中，分支[Branch]具有很重要的意义。函数调用、中断产生时程序的跳转、OS中的Multiple Task的切换等等这些均属于分支范畴，说的直白点就是根据需求合理的控制执行流。执行这些跳转共有一个特征：还需要再返回到跳转前的Point。怎么记录需要返回到哪里？多层级的调用和返回都是有顺序的，怎么保证这些顺序？跳转前如有执行的环境怎么原封不动地保存？这样返回时才能继续之前的工作。程序执行的环境或者说执行流从CPU层次来看主要包括哪些核心内容？本篇文章重点介绍这些内容。</summary></entry><entry><title type="html">交换机专栏的组织形式及内容</title><link href="https://www.bahutou.cn/2018/05/19/content-about-switch-column/" rel="alternate" type="text/html" title="交换机专栏的组织形式及内容" /><published>2018-05-19T00:00:00+08:00</published><updated>2018-05-19T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/05/19/content-about-switch-column</id><content type="html" xml:base="https://www.bahutou.cn/2018/05/19/content-about-switch-column/">&lt;p&gt;交换机专栏主要涉及两个内容，使用交换机搭建小型园区网络、交换机内部原理。使用交换机搭建小型网络可以帮助你从更直观的角度理解TCP/IP协议栈以及应用，同时，你像常见的一些网络概念 IP 、Mask 、 GateWay 、 DNS 等有一个直观且全面的理解。交换机内部原理篇则重点关注交换机内部的硬件、软件设计，给一些爱好者解开传统交换机的神秘面纱，也给爱好者们提供一些入门思路。&lt;/p&gt;

&lt;h3 id=&quot;交换机应用篇&quot;&gt;交换机应用篇&lt;/h3&gt;

&lt;p&gt;交换机应用这一主题我计划使用一个校园网（园区网）作为演示案例，该网络使用3层架构：接入层（Access）、汇聚层（Convergence）、核心层（Core）。当时我在的学校的校园网用户大约7000人左右，整个网络运营管理是几个核心的老师和学生进行的，从那时候开始对网络构架和网络设备感兴趣。当然，我不可能使用真实的设备进行搭建演示环境（毕竟我是穷人一枚），选择使用&lt;a href=&quot;https://www.gns3.com/&quot;&gt;GNS3&lt;/a&gt;这个网络仿真软件，开源的&lt;a href=&quot;https://github.com/GNS3&quot;&gt;GNS3 git地址&lt;/a&gt;，有较强的可扩展性。这样，基本思路就清晰了，使用GNS3这样的网络拓扑仿真软件来模拟一个实际的校园网，用于说明现有的校园网基本架构和设计到的网络概念。&lt;/p&gt;

&lt;h3 id=&quot;交换机研发篇&quot;&gt;交换机研发篇&lt;/h3&gt;

&lt;p&gt;交换机研发篇，计划从交换机设计的两个大的方面入手：交换机硬件、交换机固件（底层固件和上层的协议软件）。计划从以下几个层面进行说明：硬件（CPU、Switch IC）、底层固件（BootLoader、OS、Switch SDK）、协议层。使用的具体内容，做Switch IC 和PHY IC的也就那么几家，我这里使用Broadcom的IC及开发SDK，上层的应用协议使用开源的&lt;a href=&quot;http://www.nongnu.org/quagga/&quot;&gt;Quagga&lt;/a&gt;, &lt;a href=&quot;https://github.com/opensourcerouting/quagga&quot;&gt;Quagga Git 地址&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&quot;关于一些版权和license问题&quot;&gt;关于一些版权和License问题&lt;/h3&gt;

&lt;p&gt;交换机的硬件主要核心为交换IC，大部分都涉及版权问题。本系列博文尽量在不涉及侵权的情况下，屡清楚交换机的基本设计。&lt;/p&gt;

&lt;h3 id=&quot;引用资源&quot;&gt;引用资源&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://www.gns3.com/&quot;&gt;GNS3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/GNS3&quot;&gt;GNS3 git地址&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://www.nongnu.org/quagga/&quot;&gt;Quagga&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/opensourcerouting/quagga&quot;&gt;Quagga Git 地址&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;此交换机系列同步发布到&lt;a href=&quot;http://bahutou.cn&quot;&gt;bahutou’s blog&lt;/a&gt; 和&lt;a href=&quot;https://blog.csdn.net/column/details/21343.html&quot;&gt;CSDN的交换机专栏&lt;/a&gt;。&lt;/p&gt;</content><author><name>Linc Zhang</name></author><summary type="html">交换机专栏主要涉及两个内容，使用交换机搭建小型园区网络、交换机内部原理。使用交换机搭建小型网络可以帮助你从更直观的角度理解TCP/IP协议栈以及应用，同时，你像常见的一些网络概念 IP 、Mask 、 GateWay 、 DNS 等有一个直观且全面的理解。交换机内部原理篇则重点关注交换机内部的硬件、软件设计，给一些爱好者解开传统交换机的神秘面纱，也给爱好者们提供一些入门思路。</summary></entry><entry><title type="html">基于Docker环境开发、调试嵌入式软件（Embedded Software develop/Debug using Docker）</title><link href="https://www.bahutou.cn/2018/05/09/demo-using-the-env/" rel="alternate" type="text/html" title="基于Docker环境开发、调试嵌入式软件（Embedded Software develop/Debug using Docker）" /><published>2018-05-09T00:00:00+08:00</published><updated>2018-05-09T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/05/09/demo-using-the-env</id><content type="html" xml:base="https://www.bahutou.cn/2018/05/09/demo-using-the-env/">&lt;p&gt;本文使用一个具体的简单的Demo介绍此系列文章的Dev、Debug环境的使用方法，Dev、Debug环境都使用Docker技术提供OS层的环境隔离。以避免在搭建嵌入式开发环境上浪费时间，或者因搭建此嵌入式环境影响了其他开发环境。Docker技术可以解决以上这些困扰。开发环境使用Vi + GNU Cross  toolchain，测试环境使用Qemu仿真STM32-P103这款开发板。使用仿真软件仿真开发板也节省了大家购买硬件的开支，同时也方便在有即兴Idea时，随时进行验证。&lt;/p&gt;

&lt;h1 id=&quot;准备开发调试环境&quot;&gt;准备开发、调试环境&lt;/h1&gt;

&lt;p&gt;开发、调试环境依赖于Docker，首先安装Docker。Docker有两个版本CE（Community Edition）和 EE（Enterprise Edition），EE功能强大些，且稳定可靠，公司用，收费。我们学习用当然选择CE版本啦。&lt;a href=&quot;https://docs.docker.com/install/&quot;&gt;官方安装教程&lt;/a&gt;,不过Docker.com这个网站访问需要翻墙。不想翻墙的同学可以使用&lt;a href=&quot;https://yq.aliyun.com/articles/110806&quot;&gt;国内的aliyun&lt;/a&gt;。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Tag:使用Win10的bash的同学注意啦，由于Docker使用了Linux的cgroups和namespace等一些技术，Win10 bash并不完全支持。Docker安装在Win10 bash上不能使用。如果真想在Win10上使用Docker，请直接安装官方文档安装Docker for Win10. 底层环境直接使用Virtualbox提供Linux环境虚拟环境，Docker运行在虚拟化的Linux环境里。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;安装完成后，可以使用以下命令查看是否安装成功：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker version
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Client:
 Version:      17.09.0-ce
 API version:  1.32
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:42:38 2017
 OS/Arch:      linux/amd64

Server:
 Version:      17.09.0-ce
 API version:  1.32 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;minimum version 1.12&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
 Go version:   go1.8.3
 Git commit:   afdb6d4
 Built:        Tue Sep 26 22:41:20 2017
 OS/Arch:      linux/amd64
 Experimental: &lt;span class=&quot;nb&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;有了Docker ，就可以下载我们使用的开发、调试环境的Docker image了。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Dev:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Docker hub(官方镜像源)：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull zhanglianpin/stm32_compile_env:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Aliyun hub（阿里云镜像源）：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull registry.cn-hangzhou.aliyuncs.com/bahutou/stm32_compile_env
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;For Debug:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Docker hub(官方镜像源)：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull zhanglianpin/ucos_debug_env:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Aliyun hub（阿里云镜像源）：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull registry.cn-hangzhou.aliyuncs.com/bahutou/zhanglianpin/ucos_debug_env
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;下载完Dokcker image后，可以使用以下命令测试其是否下载成功：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker image &lt;span class=&quot;nb&quot;&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;output&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;REPOSITORY                       TAG                 IMAGE ID            CREATED             SIZE
zhanglianpin/stm32_compile_env   latest              48cd33a2339f        3 days ago          527MB
zhanglianpin/ucos_debug_env      latest              8d3c1b84e93f        3 days ago          203MB
ubuntu                           16.04               0b1edfbffd27        11 days ago         113MB
ubuntu                           14.04               8cef1fa16c77        11 days ago         223MB
linuxep/lepv0.1                  latest              92e0fb0aa864        7 months ago        785MB
hello-world                      latest              05a3bd381fc2        7 months ago        1.84kB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;从上面的输出我们可以看到，我的本地Docker iamge包含了 zhanglianpin/stm32_compile_env和zhanglianpin/ucos_debug_env这两个image。&lt;/p&gt;

&lt;p&gt;怎么使用这两个Docker image呐？看下面：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt;  zhanglianpin/stm32_compile_env arm-none-eabi-gcc &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Using built-in specs.
&lt;span class=&quot;nv&quot;&gt;COLLECT_GCC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm-none-eabi-gcc
&lt;span class=&quot;nv&quot;&gt;COLLECT_LTO_WRAPPER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/opt/gcc-arm-none-eabi-7-2017-q4-major/bin/../lib/gcc/arm-none-eabi/7.2.1/lto-wrapper
Target: arm-none-eabi
Configured with: /tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/src/gcc/configure &lt;span class=&quot;nt&quot;&gt;--target&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;arm-none-eabi &lt;span class=&quot;nt&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/install-native &lt;span class=&quot;nt&quot;&gt;--libexecdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/install-native/lib &lt;span class=&quot;nt&quot;&gt;--infodir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/install-native/share/doc/gcc-arm-none-eabi/info &lt;span class=&quot;nt&quot;&gt;--mandir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/install-native/share/doc/gcc-arm-none-eabi/man &lt;span class=&quot;nt&quot;&gt;--htmldir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/install-native/share/doc/gcc-arm-none-eabi/html &lt;span class=&quot;nt&quot;&gt;--pdfdir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/install-native/share/doc/gcc-arm-none-eabi/pdf &lt;span class=&quot;nt&quot;&gt;--enable-languages&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;c,c++ &lt;span class=&quot;nt&quot;&gt;--enable-plugins&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-decimal-float&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-libffi&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-libgomp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-libmudflap&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-libquadmath&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-libssp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-libstdcxx-pch&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-nls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-shared&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-threads&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--disable-tls&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-gnu-as&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-gnu-ld&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-newlib&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-headers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;yes&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-python-dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;share/gcc-arm-none-eabi &lt;span class=&quot;nt&quot;&gt;--with-sysroot&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/install-native/arm-none-eabi &lt;span class=&quot;nt&quot;&gt;--build&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;x86_64-linux-gnu &lt;span class=&quot;nt&quot;&gt;--host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;x86_64-linux-gnu &lt;span class=&quot;nt&quot;&gt;--with-gmp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/build-native/host-libs/usr &lt;span class=&quot;nt&quot;&gt;--with-mpfr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/build-native/host-libs/usr &lt;span class=&quot;nt&quot;&gt;--with-mpc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/build-native/host-libs/usr &lt;span class=&quot;nt&quot;&gt;--with-isl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/build-native/host-libs/usr &lt;span class=&quot;nt&quot;&gt;--with-libelf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;/tmp/jenkins/jenkins-GCC-7-build_toolchain_docker-633_20171130_1512067137/build-native/host-libs/usr &lt;span class=&quot;nt&quot;&gt;--with-host-libstdcxx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-pkgversion&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'GNU Tools for Arm Embedded Processors 7-2017-q4-major'&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--with-multilib-list&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;rmprofile
Thread model: single
gcc version 7.2.1 20170904 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;release&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;ARM/embedded-7-branch revision 255204] &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;GNU Tools &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;Arm Embedded Processors 7-2017-q4-major&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt;  zhanglianpin/ucos_debug_env  qemu-system-gnuarmeclipse &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GNU ARM Eclipse 64-bits QEMU emulator version 2.8.0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;v2.8.0-644-ge45e0e1-dirty&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Copyright &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;c&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 2003-2016 Fabrice Bellard and the QEMU Project developers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;相信你应该有一些感觉了吧，使用这个Docker还是挺爽的，轻开销地提供环境隔离，爽到爆。是不是你一直梦寐以求的类，反正我为各种开发、测试环境弄得烦躁的时候还是有的，这下终于可以心平气和地做开发工作了。&lt;/p&gt;

&lt;h1 id=&quot;一个简单的不能再简单的例子&quot;&gt;一个简单的不能再简单的例子&lt;/h1&gt;

&lt;p&gt;Demo：使用STM32-P103这个开发板做一个最简单的“5+4”, R0=0x05   R1=0x04  把结果0X09放到R2中 。
直接上代码（add.s）：&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;/**&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;******************************************************************************&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;file&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;author&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;Linc&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Zhang&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;V1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;date&lt;/span&gt;      &lt;span class=&quot;mi&quot;&gt;02&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;05&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2018&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;brief&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;some&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cortex&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instruction&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;******************************************************************************&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;*/&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thumb&lt;/span&gt;                       &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;same&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;saying&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;syntax&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unified&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;text&lt;/span&gt;
	&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;equ&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;STACKINIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;mh&quot;&gt;0x20005000&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;vectors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;        
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;STACKINIT&lt;/span&gt;         &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stack&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pointer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stack&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;empty&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;         &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reset&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vector&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;manually&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adjust&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;odd&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;thumb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_nmi_handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;   &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_hard_fault&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;   &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_memory_fault&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;  &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_bus_fault&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;     &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; 
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;word&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_usage_fault&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;   &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; 
&lt;span class=&quot;n&quot;&gt;_start&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;                          &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;really&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;required&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;             &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Load&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;             &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Load&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;         &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;store&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt;                   &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Infinite&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stop&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;execution&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;_dummy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;                          &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gets&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;triggered&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;just&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hang&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;loop&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_nmi_handler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_hard_fault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_memory_fault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_bus_fault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;_usage_fault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;_dummy&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;使用的Link script：&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ld&quot;&gt;
SECTIONS {
         . = 0x00000000;
         .text : { * (.text); }
		 end_code = .;
         . = 0x08000000;
         .data :AT(end_code) { * (.data); }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;使用的Makefile：&lt;/p&gt;

&lt;div class=&quot;language-make highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;AS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; arm-none-eabi-as
&lt;span class=&quot;nv&quot;&gt;CC&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; arm-none-eabi-gcc
&lt;span class=&quot;nv&quot;&gt;LD&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; arm-none-eabi-ld
&lt;span class=&quot;nv&quot;&gt;CFLAGS&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;add.elf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; 
	&lt;span class=&quot;nv&quot;&gt;$(LD)&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; main.ld &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; add.elf  add.o

&lt;span class=&quot;nl&quot;&gt;add.o&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; 
	&lt;span class=&quot;nv&quot;&gt;$(AS)&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; add.o add.s 


&lt;span class=&quot;nl&quot;&gt;.PHONY&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;clean&lt;/span&gt;

&lt;span class=&quot;nl&quot;&gt;clean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.o &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;~ core &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.elf &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;.bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Compile&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/home/work  &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; /home/work  zhanglianpin/stm32_compile_env make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;arm-none-eabi-as &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; add.o add.s 
arm-none-eabi-ld  &lt;span class=&quot;nt&quot;&gt;-T&lt;/span&gt; main.ld &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; add.elf  add.o
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Debug&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/home/work/  zhanglianpin/ucos_debug_env  qemu-system-gnuarmeclipse  &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--nographic&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;--board&lt;/span&gt; STM32-P103 &lt;span class=&quot;nt&quot;&gt;--image&lt;/span&gt; add.elf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GNU ARM Eclipse 64-bits QEMU v2.8.0 &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;qemu-system-gnuarmeclipse&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Board: &lt;span class=&quot;s1&quot;&gt;'STM32-P103'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Olimex Prototype Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F103RBT6&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Device file: &lt;span class=&quot;s1&quot;&gt;'/opt/gnuarmeclipse/qemu/2.8.0-201703022210-head/share/qemu/devices/STM32F103xx-qemu.json'&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Device: &lt;span class=&quot;s1&quot;&gt;'STM32F103RB'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Cortex-M3 r0p1, MPU, 4 NVIC prio bits, 43 IRQs&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, Flash: 128 kB, RAM: 20 kB.
Image: &lt;span class=&quot;s1&quot;&gt;'add.elf'&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Command line: &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;none&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Load     52 bytes at 0x00000000-0x00000033.
Cortex-M3 r0p1 core initialised.
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/RCC'&lt;/span&gt;, address: 0x40021000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/FLASH'&lt;/span&gt;, address: 0x40022000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/PWR'&lt;/span&gt;, address: 0x40007000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/AFIO'&lt;/span&gt;, address: 0x40010000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/EXTI'&lt;/span&gt;, address: 0x40010400, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOA'&lt;/span&gt;, address: 0x40010800, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOB'&lt;/span&gt;, address: 0x40010C00, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOC'&lt;/span&gt;, address: 0x40011000, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOD'&lt;/span&gt;, address: 0x40011400, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOE'&lt;/span&gt;, address: 0x40011800, size: 0x0400
&lt;span class=&quot;s1&quot;&gt;'/peripheral/led:red'&lt;/span&gt; 12&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;10 @&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;331,362&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; active low &lt;span class=&quot;s1&quot;&gt;'/machine/mcu/stm32/GPIOC'&lt;/span&gt;,12
QEMU 2.8.0 monitor - &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'help'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;more information
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;qemu&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Cortex-M3 r0p1 core reset.

&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;qemu&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;qemu 提供了一个monitor的UI，使用这个CLI 输入以下命令：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;info registers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;R00&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000005 &lt;span class=&quot;nv&quot;&gt;R01&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000004 &lt;span class=&quot;nv&quot;&gt;R02&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000009 &lt;span class=&quot;nv&quot;&gt;R03&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000
&lt;span class=&quot;nv&quot;&gt;R04&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R05&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R06&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R07&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000
&lt;span class=&quot;nv&quot;&gt;R08&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R09&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R10&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000
&lt;span class=&quot;nv&quot;&gt;R12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R13&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;20005000 &lt;span class=&quot;nv&quot;&gt;R14&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000000 &lt;span class=&quot;nv&quot;&gt;R15&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;00000028
&lt;span class=&quot;nv&quot;&gt;PSR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;40000173 &lt;span class=&quot;nt&quot;&gt;-Z--&lt;/span&gt; T svc32
FPSCR: 00000000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;可以看到，R00=0x05,R01=0x04,R02=0x09，确实执行了上面的  “5+4”的运算。&lt;/p&gt;

&lt;p&gt;当然你还可以使用Gdb进行程序的调试。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/home/work/   zhanglianpin/ucos_debug_env  qemu-system-gnuarmeclipse  &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--verbose&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--nographic&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;--board&lt;/span&gt; STM32-P103 &lt;span class=&quot;nt&quot;&gt;--image&lt;/span&gt; add.elf   &lt;span class=&quot;nt&quot;&gt;--gdb&lt;/span&gt; tcp::1234
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;以上命令启动了一个Gdb server，等待gdb client 去连接调试。&lt;/p&gt;

&lt;p&gt;新开一个Linux的CLI，然后输入：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/home/work  zhanglianpin/stm32_compile_env  arm-none-eabi-gdb
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;GNU gdb &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;GNU Tools &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;Arm Embedded Processors 7-2017-q4-major&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 8.0.50.20171128-git
Copyright &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;C&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &amp;lt;http://gnu.org/licenses/gpl.html&amp;gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type &lt;span class=&quot;s2&quot;&gt;&quot;show copying&quot;&lt;/span&gt;
and &lt;span class=&quot;s2&quot;&gt;&quot;show warranty&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;details.
This GDB was configured as &lt;span class=&quot;s2&quot;&gt;&quot;--host=x86_64-linux-gnu --target=arm-none-eabi&quot;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Type &lt;span class=&quot;s2&quot;&gt;&quot;show configuration&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;configuration details.
For bug reporting instructions, please see:
&amp;lt;http://www.gnu.org/software/gdb/bugs/&amp;gt;.
Find the GDB manual and other documentation resources online at:
&amp;lt;http://www.gnu.org/software/gdb/documentation/&amp;gt;.
For &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;, &lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;help&quot;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
Type &lt;span class=&quot;s2&quot;&gt;&quot;apropos word&quot;&lt;/span&gt; to search &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;commands related to &lt;span class=&quot;s2&quot;&gt;&quot;word&quot;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;gdb&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;在Gdb CLI中输入连接Gdb Server的命令：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;target remote 172.17.0.2:1234
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;blockquote&gt;
  &lt;p&gt;Tag: Docker container的IP Addr查询方法：&lt;/p&gt;
  &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker inspect &lt;span class=&quot;nt&quot;&gt;--format&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'{{ .NetworkSettings.IPAddress }}'&lt;/span&gt; container_name_or_id
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
  &lt;p&gt;查询docker container ID的方法：&lt;/p&gt;
  &lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;
&lt;/blockquote&gt;

&lt;p&gt;连接上Gdb Server之后，一切都那么熟悉了，可以使用一切Gdb调试方法了，比如你想看下Registers：&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;input:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;info all-registers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;output:&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;r0             0x5      5
r1             0x4      4
r2             0x9      9
r3             0x0      0
r4             0x0      0
r5             0x0      0
r6             0x0      0
r7             0x0      0
r8             0x0      0
r9             0x0      0
r10            0x0      0
r11            0x0      0
r12            0x0      0
sp             0x20005000       0x20005000
lr             0x0      0
pc             0x28     0x28
cpsr           0x40000173       1073742195
MSP            0x20005000       536891392
PSP            0x0      0
PRIMASK        0x0      0
BASEPRI        0x0      0
FAULTMASK      0x1      1
CONTROL        0x0      0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;自己动手搞一遍，我相信你应该知道怎么回事了，下面我捡那个重点说明一下，已经搞定的请绕行。以免耽误自己的宝贵时间。&lt;/p&gt;

&lt;p&gt;编译的时候运行的那个命令&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run &lt;span class=&quot;nt&quot;&gt;--rm&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;pwd&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;:/home/work  &lt;span class=&quot;nt&quot;&gt;-w&lt;/span&gt; /home/work zhanglianpin/stm32_compile_env make
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Docker run 的意思是运行一个Container,使用的镜像是我精心为您准备的STM32系列CPU的编译环境，–rm这个参数的含义是我运行结束后这个Container会自动删除，不保留上次运行的状态，因为我们只是单次编译下而已，没有必要保存上次Container运行的状态。 -v 这个参数的意思是让Container里面的编译环境能共享HOST主机的目录和文件，/home/work/ 这个目录是我设置的编译环境Container的默认工作目录，-w 是为Container里面的编译环境赋予写权限。zhanglianpin/stm32_compile_env是Docker iamge的名称，后面的make 是运行起来这个Container之后要执行的命令。使用Container共享HOST的文件还是很方便的，这样我就只用编译环境编译，其他的你像编辑啥的工作还是放在HOST主机上来做好了。&lt;/p&gt;

&lt;p&gt;你理解了上面的套路之后，其他的使用Docker命令应该很好理解了。&lt;/p&gt;

&lt;h1 id=&quot;简单的例子中蕴含的一些key-point&quot;&gt;简单的例子中蕴含的一些Key Point&lt;/h1&gt;

&lt;p&gt;本章节我只提出几个问题，以引起大家的思考。这些问题会在后面blog中一一解开。&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;STM32-P103上电后从哪里执行第一条指令？如何把需要执行的第一条指令放到STM32-P103需要的地方？(涉及到STM32F103RB的启动知识，链接脚本等等内容)&lt;/li&gt;
  &lt;li&gt;如果程序里有变化的量（Variable），该怎么处理？这些变量下载到哪里？存储到哪里？使用之前有什么需要注意的地方？(“Load Addr” &lt;strong&gt;VS&lt;/strong&gt; “Excute Addr”)&lt;/li&gt;
  &lt;li&gt;使用编译器编译出来的ELF文件内部到底什么结构？从静态的文件到动态的程序之间需要做哪些工作？&lt;/li&gt;
  &lt;li&gt;运行C语言需要哪些前提条件？为什么有了高级语言，汇编语言还存在？STM32-P103可以完全使用C语言开发吗？&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;本人认为理解这些事情，比较重要，理解了这些在调试一些程序BUG的时候能一针见血。&lt;/p&gt;

&lt;h1 id=&quot;引用资料说明&quot;&gt;引用资料说明&lt;/h1&gt;

&lt;p&gt;我最早的时候思考过有必要用Docker搭建Embedded software develop environment 吗？我是看了&lt;a href=&quot;https://blog.feabhas.com/2017/09/introduction-docker-embedded-developers-part-1-getting-started/&quot;&gt;An Introduction to Docker for Embedded Developers&lt;/a&gt;打消了我的顾虑。&lt;/p&gt;

&lt;p&gt;Docker 基本的概念、设计理念、使用方法最好的文档是&lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker Docs&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;Demo编程我参考了&lt;a href=&quot;https://blog.feabhas.com/2017/09/introduction-docker-embedded-developers-part-1-getting-started/&quot;&gt;An Introduction to Docker for Embedded Developers&lt;/a&gt;和&lt;a href=&quot;http://pygmy.utoh.org/riscy/cortex/led-stm32.html&quot;&gt;ARM Cortex M3 Assembly Language Example&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;qemu-system-gnuarmeclipse 的使用方法见&lt;a href=&quot;https://gnu-mcu-eclipse.github.io/qemu/options/&quot;&gt;QEMU command&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;硬件Dataheet见&lt;a href=&quot;http://www.st.com/en/microcontrollers/stm32f103rb.html&quot;&gt;Datasheet stm32f103rb&lt;/a&gt;。&lt;/p&gt;

&lt;h1 id=&quot;资源汇总&quot;&gt;资源汇总&lt;/h1&gt;
&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.docker.com/&quot;&gt;Docker Docs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.bravegnu.org/gnu-eprog/index.html&quot;&gt;Embedded Programming with the GNU Toolchain&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.feabhas.com/2017/09/introduction-docker-embedded-developers-part-1-getting-started/&quot;&gt;An Introduction to Docker for Embedded Developers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://pygmy.utoh.org/riscy/cortex/led-stm32.html&quot;&gt;ARM Cortex M3 Assembly Language Example&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.st.com/en/microcontrollers/stm32f103rb.html&quot;&gt;Datasheet stm32f103rb&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gnu-mcu-eclipse.github.io/qemu/options/&quot;&gt;QEMU command&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content><author><name>Linc Zhang</name></author><summary type="html">本文使用一个具体的简单的Demo介绍此系列文章的Dev、Debug环境的使用方法，Dev、Debug环境都使用Docker技术提供OS层的环境隔离。以避免在搭建嵌入式开发环境上浪费时间，或者因搭建此嵌入式环境影响了其他开发环境。Docker技术可以解决以上这些困扰。开发环境使用Vi + GNU Cross toolchain，测试环境使用Qemu仿真STM32-P103这款开发板。使用仿真软件仿真开发板也节省了大家购买硬件的开支，同时也方便在有即兴Idea时，随时进行验证。</summary></entry><entry><title type="html">感谢μCOS的作者Jean J.Labrosse</title><link href="https://www.bahutou.cn/2018/04/11/RTOS-article-thanks-to-author/" rel="alternate" type="text/html" title="感谢μCOS的作者Jean J.Labrosse" /><published>2018-04-11T00:00:00+08:00</published><updated>2018-04-11T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/04/11/RTOS-article-thanks-to-author</id><content type="html" xml:base="https://www.bahutou.cn/2018/04/11/RTOS-article-thanks-to-author/">&lt;p&gt;学习μCOS是我个人学习计算机科学以来比较重要的一个节点。从使用μCOS到分析、调试μCOS的所有源代码，经历了这个过程之后才让我对OS有了一个全面、可观的认识。μCOS可以说为我打开了一扇通往精彩计算机世界的窗口，让我有机会领略OS的美。这一切都依赖于Jean J.Labrosse设计了μCOS并开源出来供大家学习，在此感谢Jean J.Labrosse。&lt;/p&gt;

&lt;h1 id=&quot;感谢jean-jlabrosse&quot;&gt;感谢Jean J.Labrosse&lt;/h1&gt;

&lt;p&gt;在阅读μCOS源代码过程中，也对Jean J.Labrosse有了一定的了解，他是一个完美主义者。他写的μCOS，可谓是一个艺术品，无论从软件结构设计、编程规范、文档编写，甚至打印排版都是精益求精。完美主义体现在方方面面。阅读他写的软件可谓是一种精神享受，简单、美妙。也是从阅读了他的μCOS之后，才认识到原来软件也可以写的如此优雅。也是从那时候开始提高对自己的软件设计、编码要求，努力让自己成为一个合格的Programmer。
他写过的书籍有：&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.amazon.com/MicroC-OS-II-Kernel-CD-ROM/dp/1578201039/ref=la_B001ITVJ02_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1523411226&amp;amp;sr=1-1&quot;&gt;MicroC OS II: The Real Time Kernel &lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.amazon.com/Embedded-Systems-Building-Blocks-Ready/dp/0879306041/ref=la_B001ITVJ02_1_2?s=books&amp;amp;ie=UTF8&amp;amp;qid=1523411226&amp;amp;sr=1-2&quot;&gt;Embedded Systems Building Blocks: Complete and Ready-to-Use Modules in C&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;他创办的公司：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.micrium.com/&quot;&gt;Micrium&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;通过Jean J.Labrosse认识到了另一位嵌入式大神 &lt;a href=&quot;http://www.ganssle.com/&quot;&gt;Jack Ganssle&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;最后，向Jean J.Labrosse致谢，深深鞠一躬。&lt;/p&gt;</content><author><name>Linc Zhang</name></author><summary type="html">学习μCOS是我个人学习计算机科学以来比较重要的一个节点。从使用μCOS到分析、调试μCOS的所有源代码，经历了这个过程之后才让我对OS有了一个全面、可观的认识。μCOS可以说为我打开了一扇通往精彩计算机世界的窗口，让我有机会领略OS的美。这一切都依赖于Jean J.Labrosse设计了μCOS并开源出来供大家学习，在此感谢Jean J.Labrosse。</summary></entry><entry><title type="html">RTOS-硬件运行环境和μCOS版本说明</title><link href="https://www.bahutou.cn/2018/04/11/RTOS-dev-env/" rel="alternate" type="text/html" title="RTOS-硬件运行环境和μCOS版本说明" /><published>2018-04-11T00:00:00+08:00</published><updated>2018-04-11T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/04/11/RTOS-dev-env</id><content type="html" xml:base="https://www.bahutou.cn/2018/04/11/RTOS-dev-env/">&lt;p&gt;本系列文章中使用的软件运行环境：硬件，QEMU(STM32)仿真; 软件，μCOS-III(V3.03.01)。&lt;/p&gt;

&lt;h1 id=&quot;运行环境说明&quot;&gt;运行环境说明&lt;/h1&gt;

&lt;p&gt;为良好地说明RTOS的方方面面，必须上手亲自调试代码。为了减少CPU架构和指令集方面的理解负担，我们使用RISC指令集的CPU。基于ARM Cortex-M3处理器架构的STM32系列Soc在低功耗嵌入式领域有着比较广泛的应用。因此，我们选择这款Soc作为其硬件平台。考虑到实验的方便性和有些初学者手里还没有STM32的开发板等原因，我们使用QEMU软件仿真一个基于STM32 Soc的开发板&lt;a href=&quot;https://www.olimex.com/Products/ARM/ST/STM32-P103/&quot;&gt;STM32-P103&lt;/a&gt;。如大家有条件购买实际的开发板，建议大家购买实际的STM32开发板。&lt;/p&gt;

&lt;p&gt;针对μCOS，我们选择μCOS-III 这个版本，从官网上看这个版本是最新的，添加了一些用户反馈的新功能，比如Round Robin Scheduling。
这个版本网上资料也最多，并且这个版本除了提供基本的RTOS kernel 之外，也同时提供了TCP/IP Stack、μCOS-FS、μCOS-GUI等等基础服务。真可谓是学习RTOS的绝好材料。&lt;/p&gt;

&lt;h2 id=&quot;硬件环境&quot;&gt;硬件环境&lt;/h2&gt;

&lt;p&gt;硬件使用QEMU仿真，目前官网上QEMU的仿真支持的开发板没有STM32，万能的工程师们怎么能允许这种情况发生呐！&lt;a href=&quot;https://github.com/beckus/qemu_stm32&quot;&gt;qemu_stm32&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这个作者真是活雷锋啊，他还提供了测试这个仿真出来的STM32开发板的DEMO程序，从简单的串口打印“hello world” 到复杂的RTOS。可惜，他用的是FreeRTOS，我们要用μCOS-III。&lt;a href=&quot;https://github.com/beckus/stm32_p103_demos&quot;&gt;stm32_p103_demos&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;qemu_stm32这个软件的编译、安装请参考Project的ReadMe文件，Try it , enjoy it!!!
关于QEMU软件的使用请参考官网网站&lt;a href=&quot;https://www.qemu.org/&quot;&gt;QEMU&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;QEMU(2.11)最新版本支持的ARM 板卡有：&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;qemu-system-arm  &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Supported machines are:
akita                Sharp SL-C1000 (Akita) PDA (PXA270)
ast2500-evb          Aspeed AST2500 EVB (ARM1176)
borzoi               Sharp SL-C3100 (Borzoi) PDA (PXA270)
canon-a1100          Canon PowerShot A1100 IS
cheetah              Palm Tungsten|E aka. Cheetah PDA (OMAP310)
collie               Sharp SL-5500 (Collie) PDA (SA-1110)
connex               Gumstix Connex (PXA255)
cubieboard           cubietech cubieboard
emcraft-sf2          SmartFusion2 SOM kit from Emcraft (M2S010)
highbank             Calxeda Highbank (ECX-1000)
imx25-pdk            ARM i.MX25 PDK board (ARM926)
integratorcp         ARM Integrator/CP (ARM926EJ-S)
kzm                  ARM KZM Emulation Baseboard (ARM1136)
lm3s6965evb          Stellaris LM3S6965EVB
lm3s811evb           Stellaris LM3S811EVB
mainstone            Mainstone II (PXA27x)
midway               Calxeda Midway (ECX-2000)
mps2-an385           ARM MPS2 with AN385 FPGA image for Cortex-M3
mps2-an511           ARM MPS2 with AN511 DesignStart FPGA image for Cortex-M3
musicpal             Marvell 88w8618 / MusicPal (ARM926EJ-S)
n800                 Nokia N800 tablet aka. RX-34 (OMAP2420)
n810                 Nokia N810 tablet aka. RX-44 (OMAP2420)
netduino2            Netduino 2 Machine
none                 empty machine
nuri                 Samsung NURI board (Exynos4210)
palmetto-bmc         OpenPOWER Palmetto BMC (ARM926EJ-S)
raspi2               Raspberry Pi 2
realview-eb          ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-eb-mpcore   ARM RealView Emulation Baseboard (ARM11MPCore)
realview-pb-a8       ARM RealView Platform Baseboard for Cortex-A8
realview-pbx-a9      ARM RealView Platform Baseboard Explore for Cortex-A9
romulus-bmc          OpenPOWER Romulus BMC (ARM1176)
sabrelite            Freescale i.MX6 Quad SABRE Lite Board (Cortex A9)
smdkc210             Samsung SMDKC210 board (Exynos4210)
spitz                Sharp SL-C3000 (Spitz) PDA (PXA270)
sx1                  Siemens SX1 (OMAP310) V2
sx1-v1               Siemens SX1 (OMAP310) V1
terrier              Sharp SL-C3200 (Terrier) PDA (PXA270)
tosa                 Sharp SL-6000 (Tosa) PDA (PXA255)
verdex               Gumstix Verdex (PXA270)
versatileab          ARM Versatile/AB (ARM926EJ-S)
versatilepb          ARM Versatile/PB (ARM926EJ-S)
vexpress-a15         ARM Versatile Express for Cortex-A15
vexpress-a9          ARM Versatile Express for Cortex-A9
virt-2.10            QEMU 2.10 ARM Virtual Machine
virt                 QEMU 2.11 ARM Virtual Machine (alias of virt-2.11)
virt-2.11            QEMU 2.11 ARM Virtual Machine
virt-2.6             QEMU 2.6 ARM Virtual Machine
virt-2.7             QEMU 2.7 ARM Virtual Machine
virt-2.8             QEMU 2.8 ARM Virtual Machine
virt-2.9             QEMU 2.9 ARM Virtual Machine
xilinx-zynq-a9       Xilinx Zynq Platform Baseboard for Cortex-A9
z2                   Zipit Z2 (PXA27x)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;通过查看qemu官方文档里 3.5 ARM System emulator相关章节得知，支持的STM32 Soc的板子有：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;lm3s6965evb          Stellaris LM3S6965EVB&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;lm3s811evb           Stellaris LM3S811EVB&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我们可以基于上述这两个Board做开发、验证。&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/beckus/qemu_stm32&quot;&gt;qemu_stm32&lt;/a&gt;  这个Project里用的是QEMU2.1.3，作者添加了Olimex STM32 P103这个开发板的支持。&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./qemu-system-arm &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Supported machines are:
lm3s811evb           Stellaris LM3S811EVB
canon-a1100          Canon PowerShot A1100 IS
vexpress-a15         ARM Versatile Express for Cortex-A15
vexpress-a9          ARM Versatile Express for Cortex-A9
xilinx-zynq-a9       Xilinx Zynq Platform Baseboard for Cortex-A9
connex               Gumstix Connex (PXA255)
n800                 Nokia N800 tablet aka. RX-34 (OMAP2420)
lm3s6965evb          Stellaris LM3S6965EVB
versatileab          ARM Versatile/AB (ARM926EJ-S)
borzoi               Borzoi PDA (PXA270)
tosa                 Tosa PDA (PXA255)
cheetah              Palm Tungsten|E aka. Cheetah PDA (OMAP310)
midway               Calxeda Midway (ECX-2000)
mainstone            Mainstone II (PXA27x)
n810                 Nokia N810 tablet aka. RX-44 (OMAP2420)
terrier              Terrier PDA (PXA270)
stm32-maple          OPEN SOURCE HARDWARE MAPLE / ARDUINO LIKE DEVELOPMENT BOARD
highbank             Calxeda Highbank (ECX-1000)
cubieboard           cubietech cubieboard
sx1-v1               Siemens SX1 (OMAP310) V1
sx1                  Siemens SX1 (OMAP310) V2
realview-eb-mpcore   ARM RealView Emulation Baseboard (ARM11MPCore)
kzm                  ARM KZM Emulation Baseboard (ARM1136)
akita                Akita PDA (PXA270)
z2                   Zipit Z2 (PXA27x)
musicpal             Marvell 88w8618 / MusicPal (ARM926EJ-S)
stm32-p103           Olimex STM32 p103 Dev Board
realview-pb-a8       ARM RealView Platform Baseboard for Cortex-A8
versatilepb          ARM Versatile/PB (ARM926EJ-S)
realview-eb          ARM RealView Emulation Baseboard (ARM926EJ-S)
realview-pbx-a9      ARM RealView Platform Baseboard Explore for Cortex-A9
spitz                Spitz PDA (PXA270)
none                 empty machine
virt                 ARM Virtual Machine
collie               Collie PDA (SA-1110)
smdkc210             Samsung SMDKC210 board (Exynos4210)
verdex               Gumstix Verdex (PXA270)
nuri                 Samsung NURI board (Exynos4210)
integratorcp         ARM Integrator/CP (ARM926EJ-S)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;可以看到新添加了以下两个Cortex-M3的开发板：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;stm32-maple          OPEN SOURCE HARDWARE MAPLE / ARDUINO LIKE DEVELOPMENT BOARD&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;stm32-p103           Olimex STM32 p103 Dev Board&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;最近又查阅了些关于Cortex-m3使用GNU Toolchain开发的相关资料，发现了一个支持大部分Cortex-m3 处理器的改进版&lt;a href=&quot;https://github.com/zhanglianpin/qemu&quot;&gt;QEMU&lt;/a&gt;。支持绝大部分基于Cortex-m3的开发板。&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;qemu-system-gnuarmeclipse &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Supported boards:
  Maple                LeafLab Arduino-style STM32 microcontroller board &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;r5&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  NUCLEO-F103RB        ST Nucleo Development Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32 F1 series
  NUCLEO-F411RE        ST Nucleo Development Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32 F4 series
  NetduinoGo           Netduino GoBus Development Board with STM32F4
  NetduinoPlus2        Netduino Development Board with STM32F4
  OLIMEXINO-STM32      Olimex Maple &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Arduino-like&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; Development Board
  STM32-E407           Olimex Development Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F407ZGT6
  STM32-H103           Olimex Header Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F103RBT6
  STM32-P103           Olimex Prototype Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F103RBT6
  STM32-P107           Olimex Prototype Board &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F107VCT6
  STM32F0-Discovery    ST Discovery kit &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F051 line
  STM32F4-Discovery    ST Discovery kit &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F407/417 lines
  STM32F429I-Discovery ST Discovery kit &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;STM32F429/439 lines
  generic              Generic Cortex-M board&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; use &lt;span class=&quot;nt&quot;&gt;-mcu&lt;/span&gt; to define the device
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;这个针对Cortex-m3改进版的QEMU的详细介绍&lt;/strong&gt;&lt;a href=&quot;https://gnu-mcu-eclipse.github.io/qemu/&quot;&gt;The GNU MCU Eclipse QEMU&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GNU MCU Eclipse QEMU的COMMAND的使用方法&lt;/strong&gt;&lt;a href=&quot;https://gnu-mcu-eclipse.github.io/qemu/options/&quot;&gt;The GNU MCU Eclipse QEMU command line options&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;结论：&lt;/strong&gt;
开发板选择Olimex STM32 p103，硬件模拟器选择&lt;a href=&quot;https://gnu-mcu-eclipse.github.io/qemu/&quot;&gt;The GNU MCU Eclipse QEMU&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;关于开发板的输入输出：一般嵌入式开发中不能使用通用lib库（提供基本的输入输出系统等），因为通用库是基于OS（Linux、Unix、Windos）提供的服务的。我们嵌入式开发有时候涉及到裸（bare metal）开发，那就得对程序的来龙去脉有更好的掌握。有的嵌入式集成开发环境（keil、DS-5）提供一定的IO库，为程序员提供标准的printf scanf等函数，使用串口作为物理输入输出接口。这样的话，针对不同的硬件开发板还需要处理uart的初始化和使用的细节问题，不是很方面。ARM提供了一个叫Semihosting的技术，程序运行在目标平台上，需要使用输入输出这些资源时，通过调试接口（JLINK）调用HOST开发主机的键盘输入资源和显示资源。我们使用的QEMU支持这个Semihosting技术，所有的输入输出都使用这项技术，解决了目标开发板的输入输出问题。这项技术之用在开发阶段，产品成型阶段当然要实现自己的IO喽。不过，我们这里仅仅Debug代码，因此使用Semihosting技术比较合适。一图胜千言：
&lt;img src=&quot;/images/posts/2018-04-11-RTOS-dev-env/Semihosting.png&quot; alt=&quot;Semihosting overview&quot; title=&quot;Semihosting overview&quot; /&gt;&lt;/p&gt;

&lt;p&gt;对这个技术感兴趣的可以看这里：&lt;a href=&quot;http://www.keil.com/support/man/docs/armcc/armcc_pge1358787045051.htm&quot;&gt;ARM Semihosting&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;软件环境&quot;&gt;软件环境&lt;/h2&gt;

&lt;p&gt;软件使用 μCOS-III(V3.03.01),我们直接下载μCOS-III基于STM32开发板的版本。
下载地址：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://www.micrium.com/downloadcenter/&quot;&gt;Download μCOS-III&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;官网上的开发环境一般是基于Keil 或者IAR的，这种集成开发环境适合工程开发，并不适合入门学习，因为好多东西都自动化了，不利于学习者学习掌握核心重点，因此我们使用GNU Tools(GCC、GDB)来做编译、调试。我们使用的GNU tools 上面已经介绍了。&lt;/p&gt;

&lt;h2 id=&quot;开发环境&quot;&gt;开发环境&lt;/h2&gt;

&lt;p&gt;编译器使用gnu交叉编译器编译，编译器下载链接：&lt;a href=&quot;https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads&quot;&gt;GNU Arm Embedded Toolchain&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;开发嵌入式软件准备环境还是挺繁琐又没技术含量的事情，当我接触了Docker之后，一切都改变了，Docker可以帮你快速部署开发环境，又不破坏其他的开发环境。Docker提供了OS级别上的运行环境隔离。关于Dcoker的基本概念和基本使用方法参见&lt;a href=&quot;https://docs.docker.com/engine/docker-overview/&quot;&gt;Docker user manual&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;因此，我计划发布两个Docker image：&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://hub.docker.com/r/zhanglianpin/stm32_compile_env/&quot;&gt;Build environment docker image&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;a href=&quot;https://hub.docker.com/r/zhanglianpin/ucos_debug_env/&quot;&gt;Debug environment using qemu docker image&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;如果你访问Docker慢的话，请选择使用国内aliyun&lt;/p&gt;

&lt;p&gt;Build environment docker image：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull registry.cn-hangzhou.aliyuncs.com/bahutou/stm32_compile_env
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Debug environment using qemu docker image：&lt;/p&gt;
&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker pull registry.cn-hangzhou.aliyuncs.com/bahutou/ucos_debug_env
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;关于这两个Docker image的具体使用方法具体见后面的使用qemu调试Cortex-M3 程序的demo。&lt;/p&gt;

&lt;p&gt;生成Docker image的Dockerfile 托管在github上，如果你想自己定制Docker image，你可以修改Dockerfile，然后自己动手build。&lt;/p&gt;

&lt;p&gt;Dockerfile地址：
Build environment Dockerfile：&lt;a href=&quot;https://github.com/zhanglianpin/stm32_compile_env&quot;&gt;Build environment Dockerfile&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Debug environment Dockerfile：&lt;a href=&quot;https://github.com/zhanglianpin/ucos_debug_env&quot;&gt;Debug environment Dockerfile&lt;/a&gt;&lt;/p&gt;

&lt;h1 id=&quot;引用资源&quot;&gt;引用资源&lt;/h1&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/zhanglianpin/qemu&quot;&gt;STM32仿真软件&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/zhanglianpin/stm32_p103_demos&quot;&gt;P103开发板测试代码&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.olimex.com/Products/ARM/ST/STM32-P103/&quot;&gt;P103开发板资料下载地址&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.st.com/en/microcontrollers/stm32f103rb.html&quot;&gt;STM32-SOC-STM32F103RB资料地址&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.micrium.com/&quot;&gt;uCOS资料下载&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.feabhas.com/2017/09/introduction-docker-embedded-developers-part-1-getting-started/&quot;&gt;Develop embedded software using Docker&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content><author><name>Linc Zhang</name></author><summary type="html">本系列文章中使用的软件运行环境：硬件，QEMU(STM32)仿真; 软件，μCOS-III(V3.03.01)。</summary></entry><entry><title type="html">RTOS专栏-目录</title><link href="https://www.bahutou.cn/2018/04/09/RTOS-article-list/" rel="alternate" type="text/html" title="RTOS专栏-目录" /><published>2018-04-09T00:00:00+08:00</published><updated>2018-04-09T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/04/09/RTOS-article-list</id><content type="html" xml:base="https://www.bahutou.cn/2018/04/09/RTOS-article-list/">&lt;p&gt;使用一个实际项目的案例来引出使用RTOS的必要性，然后总结出μCOS的核心内容以及理解这些内容需要的前提知识，做出专栏的详细章节目录。&lt;/p&gt;

&lt;h1 id=&quot;why-rtos-&quot;&gt;WHY RTOS ???&lt;/h1&gt;

&lt;p&gt;真正理解使用RTOS的好处还得是经历过实际的Project，说一个我工作以后接触到的第一个Project吧。该项目是一个嵌入式控制器，需要做的工作有：读取A/D数据、根据读取到的A/D数据计算结果、和上位机通讯、显示、用户按键。详细一点的技术要求，对实时性要求比较高的一个任务是读取A/D数据，需要精确的10ms 级别interval的读取。这样的系统从直觉上来看，有很多任务要去做，而且任务之间从重要性、紧迫性方面比较的话还不能一视同仁。如果不使用RTOS的话，经典的做法是使用 &lt;strong&gt;前后台系统&lt;/strong&gt; 设计方法，后台系统作为一个大的Loop检测各种Event，前台是各种外部事件的中断，比如读取到A/D数据、检测到外部按键等等。这种系统要想实现特定事件的实时响应和不同事件的紧急度管理还是需要很多的额外工作需要做。其实说的直白点，一个小型嵌入式系统的核心控制器一般都是一个综合了CPU和外设的片上系统。这个核心控制器一般CPU是单core的，只能提供一个执行流，再加上Interrupt，可以说整体就有了两个可管理的执行流，且中断的执行流优先级要大于CPU提供的执行流。这就是前后台系统设计的自然性，硬件提供了两个执行流，我就利用这两个执行流设计了前后台系统。前台是各种中断事件，后台利用CPU提供的计算资源做逻辑处理。&lt;/p&gt;

&lt;p&gt;如果利用软件管理手段能把CPU上的执行流管理起来，势必能加速整体的吞吐量和实时响应能力。因为CPU上的执行流从宏观上来看利用CPU进行运算的时间是间隔的，这个也很好理解，因为CPU运算能力是很强的，但是一个任务一般会涉及到等待外部事件，外部事件发生后才去做逻辑处理或者数值运算。在等待外部相对于CPU运算来说慢的多的多的事件时，如果能把CPU让给其他任务来用，那CPU的整体利用率就很高了。真是不错的想法。一个嵌入式产品不可能不与外部交互，毕竟科技产品是为人服务的。&lt;/p&gt;

&lt;p&gt;使用RTOS后，设计上述Project就可以比较轻松地管理各个任务，还能很容易根据任务的紧迫性、实时性来区分对待。这样一来，对降低嵌入式软件的设计复杂度很有帮助，后期调试、维护也比较容易。这样也比较自然，本来不同的任务被划分出来也是根据这个任务做的工作具有高内聚的特点，和其他任务交互具有低耦合的特点，把一个任务作为一个管理单元确实比较自然。使用RTOS后，每一个任务都认为自己独占一整个CPU，实际上只是各个任务分时复用CPU资源。各个任务既然划分出来了，必然涉及到各个任务之间通讯的问题，RTOS也提供了各种IPC通讯的方法。这样设计出来的嵌入式软件确实符合“高内聚、低耦合”的设计原则。&lt;/p&gt;

&lt;p&gt;RTOS核心就是管理CPU，管理CPU的意思就是能抽象出多个执行流(Task/Thread)。RTOS提供的其他服务都和外部IO有关系，你像FS(File System)、Device Manegement等等。&lt;/p&gt;

&lt;p&gt;RTOS提供了一个对程序员来说更好用的抽象的计算机，这个抽象的计算机屏蔽了底层硬件细节并提供了很多基础服务。这就是使用RTOS的原因，相信你使用过RTOS设计产品后，你就不会再使用前后台系统设计产品了。&lt;/p&gt;

&lt;h1 id=&quot;需要理解的几个基本概念&quot;&gt;需要理解的几个基本概念&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;何为操作系统？何为实时操作系统？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;RTOS 中硬件平台无关性代码和硬件平台有关性代码&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;既然都有了高级语言，为什么汇编语言还存在？RTOS源代码中汇编语言的作用主要是什么？&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;程序员编写的程序从源代码到实际运行都经历了什么？(源代码—目标映像—实际运行)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;重新认识下栈[Stack]。(栈和C语言的关系、栈和Thread运行环境的关系)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;目录&quot;&gt;目录&lt;/h1&gt;

&lt;h2 id=&quot;感谢μcos的作者jean-jlabrosse&quot;&gt;感谢μCOS的作者Jean J.Labrosse&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.bahutou.cn/2018/04/11/RTOS-article-thanks-to-author/&quot;&gt;感谢μCOS的作者Jean J.Labrosse&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;硬件运行环境和μcos版本说明&quot;&gt;硬件运行环境和μCOS版本说明&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.bahutou.cn/2018/04/11/RTOS-dev-env&quot;&gt;硬件运行环境和μCOS版本说明&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;基于docker环境开发调试嵌入式软件&quot;&gt;基于Docker环境开发、调试嵌入式软件&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.bahutou.cn/2018/05/09/demo-using-the-env/&quot;&gt;基于Docker环境开发、调试嵌入式软件&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;依赖的知识点&quot;&gt;依赖的知识点&lt;/h2&gt;
&lt;h3 id=&quot;操作系统实时操作系统&quot;&gt;操作系统&amp;amp;&amp;amp;实时操作系统&lt;/h3&gt;
&lt;h3 id=&quot;硬件平台有关平台无关&quot;&gt;硬件平台有关&amp;amp;&amp;amp;平台无关&lt;/h3&gt;
&lt;h3 id=&quot;汇编语言存在的意义&quot;&gt;汇编语言存在的意义&lt;/h3&gt;
&lt;h3 id=&quot;程序的生老病死&quot;&gt;程序的生老病死&lt;/h3&gt;

&lt;p&gt;(源代码—目标映像—实际运行)&lt;/p&gt;

&lt;h3 id=&quot;重新认识下栈stack&quot;&gt;重新认识下栈[Stack]&lt;/h3&gt;

&lt;p&gt;(栈和C语言的关系、栈和Thread运行环境的关系)&lt;/p&gt;

&lt;h3 id=&quot;μcos中管理cpu需要用到的stm32硬件知识&quot;&gt;μCOS中管理CPU需要用到的STM32硬件知识&lt;/h3&gt;</content><author><name>Linc Zhang</name></author><summary type="html">使用一个实际项目的案例来引出使用RTOS的必要性，然后总结出μCOS的核心内容以及理解这些内容需要的前提知识，做出专栏的详细章节目录。</summary></entry><entry><title type="html">RTOS专栏</title><link href="https://www.bahutou.cn/2018/04/08/catalogs-about-RTOS/" rel="alternate" type="text/html" title="RTOS专栏" /><published>2018-04-08T00:00:00+08:00</published><updated>2018-04-08T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/04/08/catalogs-about-RTOS</id><content type="html" xml:base="https://www.bahutou.cn/2018/04/08/catalogs-about-RTOS/">&lt;p&gt;操作系统作为硬件和软件的中间衔接媒介，起到了承上启下的作用。深刻理解操作系统原理对理解抽象、层次、接口等计算机科学中核心的概念具有很大的帮助。操作系统屏蔽了底层硬件操作细节，管理了CPU、MEM、Device等硬件资源并对上提供了简易的操作接口。&lt;/p&gt;

&lt;p&gt;个人认为作为中间件的操作系统主要解决了两个痛点：&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;1，向下屏蔽了底层硬件操作细节。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;2，向上提供了Task Management、IPC、File System、Device Management等基础服务。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;rtos-专栏简介&quot;&gt;RTOS 专栏简介&lt;/h3&gt;

&lt;p&gt;对计算机科学感兴趣起于认识交换机、路由器、防火墙、服务器这些有各种灯一闪一闪的长得很高冷的这些家伙，进一步认识他们是通过Linux这个操作系统。上大学的时候可谓是比较着迷，上述设备就能把全世界的PC互联，让你在家就能接收到世界上最新的咨询、最好的资料，真是太神奇了。我花了一年的时间把这些家伙的脾性都摸透了，和他们玩的不亦乐乎。不过，我并不甘心，我想知道这些家伙的内心是怎样的？随即咨询了几个做信息化建设的老师，他们回答惊奇的一致：”我们的爱好在于如何利用这些家伙提供优良的服务，至于这些家伙里面咋回事，我们不关心，你要是有兴趣，我给你推荐个老师，他对这些家伙里面感兴趣，也很有研究“。后来我就来到了”嵌入式系统结构实验室“，一呆就是2年，在这里我接触到了比搭建网络服务更底层的一些东西，比如CPU如何工作，操作系统都干了什么，模拟电路和数字电路都是啥玩意，如何用基本的数字电路搭建微型计算机等等。&lt;/p&gt;

&lt;p&gt;各位看官别着急，马上到重点。到了嵌入式体系结构实验室以后，认识了我人生中比较重要的一位老师—刘老师。他看我比较有诚意，对计算机也比较有兴趣，就跟我说：“服务器那种计算机功能太全，不适合找准主线和核心，容易迷失在繁琐的技术细节里，我建议你买个51单片机开发板，把51单片机说明书里的功能都自己写代码耍耍。51单片机虽然说是小，但麻雀虽小，五脏俱全。等你有感觉了，找我来，我给你找个小活玩玩”。我当时也是半信半疑，不过我的直觉告诉我这个老师是搞工程的，说的还算务实。就按他说的办，不过，我没买51单片机，用的是实验室里师哥留下的一个小51开发板，上面都落了好多土了。因为之前有信息化建设中编码的经验以及专业课也在学计算机组成原理，闹明白这个51单片机还是不在话下。弄好了之后，老师先让我总结了一下你觉着单片机主要核心有哪些？我就随口说了句：“能根据我的指令处理逻辑，还有外部事件可以打断它，处理完外部事件，它还能继续干活”。我老师说：“你小子还真行”。后来，做了一个“检测面粉湿度”的小活，发现一个具体项目需要好多任务，比如读取AD传感器数据，处理显示，接收用户按键等等。自己直接写程序的话，需要自己处理这些任务以及这些任务之间的通讯问题，使用的是一个大循环，检测各种事件的发生，一旦发生就处理相应事件。但有些时候处理事件的实时响应性差，其实我也知道单片机处理逻辑和计算的速度比人计算的要快多了，整体性能差是因为外部的各种设备慢，就像你大脑运算很快，但是自己的手脚运动缓慢，整体来看还是挺慢的。要是一个任务在等待处理外部慢的事件时，单片机的CPU就空闲下来了，要是这个时间能做其他任务里逻辑处理工作的话，整个系统的处理能力就很好了。这个时候老师就说：“其实，这些问题别人已经帮助解决了，你看看μCOS吧” 。“μCOS？我一脸懵逼，不过，根据之前跟这位老师相处的经验，他不会乱说的，先记下来，然后在查资料吧”
后来，了解了μCOS后，对操作系统的核心概念有了很直观的认识，况且我是因为要解决我的问题才去找的资料，学习的μCOS，所以学习起来比较自然，也被国外的程序员的严谨，聪明所折服。&lt;/p&gt;

&lt;p&gt;各位看官也明白了，我对计算机内部构造的了解方法是：&lt;strong&gt;51单片机+μCOS&lt;/strong&gt;。51单片机告诉我CPU是啥？咋用？ μCOS 告诉我怎么最高效地利用CPU,怎么设计复杂软件？&lt;/p&gt;

&lt;p&gt;μCOS是一个开源的、实时性的小型嵌入式操作系统。代码量小，很适合操作系统的入门学习。&lt;/p&gt;

&lt;p&gt;最好的学习方法是：&lt;strong&gt;Reading The Source Code  &amp;amp;&amp;amp; Debug in Real Hardware…&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;如果你能阅读源代码，并调试，而且还有实际应用经验的话，这个系列的blog你就不用看了。你已经具备了计算机知识学习能力，看这些别人嚼过的资料纯属浪费时间。&lt;/p&gt;

&lt;p&gt;相关资源：&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://download.csdn.net/download/zhanglianpin/10332982&quot;&gt;μcos-ii书籍和源代码&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://download.csdn.net/download/zhanglianpin/10335287&quot;&gt;μcos-iii书籍和源代码&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;这个系列blog是对我原来CSDN博客关于μCOS部分的完善和更新，工作后对操作系统又有了新的认识和观点。再回头看上学时写的博客，无论从格式上还是内容结构上都需要改进和优化。因此计划重新写一个系列，此系列同步发布到&lt;a href=&quot;http://bahutou.cn&quot;&gt;bahutou’s blog&lt;/a&gt; 和&lt;a href=&quot;https://blog.csdn.net/column/details/21340.html&quot;&gt;CSDN的μCOS专栏&lt;/a&gt;。&lt;/p&gt;</content><author><name>Linc Zhang</name></author><summary type="html">操作系统作为硬件和软件的中间衔接媒介，起到了承上启下的作用。深刻理解操作系统原理对理解抽象、层次、接口等计算机科学中核心的概念具有很大的帮助。操作系统屏蔽了底层硬件操作细节，管理了CPU、MEM、Device等硬件资源并对上提供了简易的操作接口。</summary></entry><entry><title type="html">交换机专栏</title><link href="https://www.bahutou.cn/2018/04/08/catalogs-about-switch/" rel="alternate" type="text/html" title="交换机专栏" /><published>2018-04-08T00:00:00+08:00</published><updated>2018-04-08T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/04/08/catalogs-about-switch</id><content type="html" xml:base="https://www.bahutou.cn/2018/04/08/catalogs-about-switch/">&lt;p&gt;计算机发展史上，有两个比较重要的地方，第一个是制造出了能接收用户指令的半自动运算装置—冯.诺依曼机器; 第二个是发明了互联网，将成千上万台机器互联。而交换机是实现将多台电脑互联起来的重要通讯基础设备，因它一般在大楼的弱电间里，非信息化维护人员一般见不到，交换机就像后台工作者，默默无闻地为成千上万机器提供互相通讯的通道。本专栏，从交换机的应用层—实际规划中小型网络到交换机研发层—设计、研发标准三层交换机，详细介绍交换机如何将成千上万的电脑互联起来，以及交换机内部的原理和构造。&lt;/p&gt;

&lt;h3 id=&quot;交换机-专栏简介&quot;&gt;交换机 专栏简介&lt;/h3&gt;

&lt;p&gt;我跟交换机有比较多的渊源，大学里因为在信息化中心做网络建设、维护工作见到了大量的交换机设备。一开始仅仅是学习各个设备的操作方法，那时候对 &lt;strong&gt;Command&lt;/strong&gt; 操作方式还很好奇，觉着在黑乎乎的界面里敲击键盘还挺神秘。后来学习到了几千用户的校园网的架构和拓扑知识，以及如何规划中小型网络。宏观的应用搞清楚了，就像看看交换机内部啥构造？是什么结构？敲击的命令行都干啥了？这些知识咨询当时的学长和老师，他们也不能说的很清楚，但是自己一直对这种专用计算设备很感兴趣，上学时也就是理解一些TCP/IP协议栈的知识，还有一些基本的二层交换原理和三层交换原理。&lt;/p&gt;

&lt;p&gt;工作后，有机会涉及到交换机设备的研发工作，才得以把交换机的内部原理和构造给搞明白。&lt;/p&gt;

&lt;p&gt;本专栏从两个层面介绍交换机：应用层面和研发层面。 这样比较有意思，宏观和微观层面都有了，可以让大家对交换机这种设备有个比较全面的了解。&lt;/p&gt;

&lt;p&gt;此交换机系列同步发布到&lt;a href=&quot;http://bahutou.cn&quot;&gt;bahutou’s blog&lt;/a&gt; 和&lt;a href=&quot;https://blog.csdn.net/column/details/21343.html&quot;&gt;CSDN的交换机专栏&lt;/a&gt;。&lt;/p&gt;</content><author><name>Linc Zhang</name></author><summary type="html">计算机发展史上，有两个比较重要的地方，第一个是制造出了能接收用户指令的半自动运算装置—冯.诺依曼机器; 第二个是发明了互联网，将成千上万台机器互联。而交换机是实现将多台电脑互联起来的重要通讯基础设备，因它一般在大楼的弱电间里，非信息化维护人员一般见不到，交换机就像后台工作者，默默无闻地为成千上万机器提供互相通讯的通道。本专栏，从交换机的应用层—实际规划中小型网络到交换机研发层—设计、研发标准三层交换机，详细介绍交换机如何将成千上万的电脑互联起来，以及交换机内部的原理和构造。</summary></entry><entry><title type="html">使用Jekyll和github-pages搭建个人blog系统</title><link href="https://www.bahutou.cn/2018/02/27/blog-by-jekyll&&github-pages/" rel="alternate" type="text/html" title="使用Jekyll和github-pages搭建个人blog系统" /><published>2018-02-27T00:00:00+08:00</published><updated>2018-02-27T00:00:00+08:00</updated><id>https://www.bahutou.cn/2018/02/27/blog-by-jekyll&amp;&amp;github-pages</id><content type="html" xml:base="https://www.bahutou.cn/2018/02/27/blog-by-jekyll&amp;&amp;github-pages/">&lt;p&gt;朋友，你是否也想拥有一个自主可控的blog系统？先看看我自己的博客：&lt;a href=&quot;http://www.bahutou.cn&quot;&gt;bahutou’s blog&lt;/a&gt;。现在就可以用很低的成本实现，这篇文章就详细描述了如何利用现有的开源技术(Jekyll github-pages)搭建属于自己的blog系统。开始行动吧，小伙伴！&lt;/p&gt;

&lt;h3 id=&quot;动机&quot;&gt;动机&lt;/h3&gt;

&lt;p&gt;一直以来就很喜欢分享知识，使用过CSDN、CNBLOG、51CTO，使用最多的博客系统是CSDN，在此感谢CSDN提供这样的技术分享平台。但总感觉没有找到那种随心所欲编写的那种快感。后来看到一篇博文&lt;a href=&quot;http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html&quot; title=&quot;Blogging Like a Hacker&quot;&gt;Blogging Like a Hacker&lt;/a&gt; ，触动了我的心弦。对啊，写blog就应该只关注内容，其他的都是辅助，并不是重点。核心的重点就是你的想法能顺畅的表达，排版是顺带手的。这次爽了，用合适方法去做有意思的事情。我就有了动手搭建属于自己的顺畅书写小天地的动机。技术当然也选定了：&lt;a href=&quot;https://github.com/topics/jekyll&quot; title=&quot;jekyll&quot;&gt;Jekyll&lt;/a&gt;+&lt;a href=&quot;https://github.com/topics/github-pages&quot; title=&quot;github-pages&quot;&gt;github-pages&lt;/a&gt;。&lt;/p&gt;

&lt;h3 id=&quot;整体套路介绍&quot;&gt;整体套路介绍&lt;/h3&gt;

&lt;p&gt;干啥事情都得有个名字，所谓&lt;em&gt;名正而言顺&lt;/em&gt;。自己的blog也得有个个性的名字—域名(用于在网络中识别一个具体的Host)。然后我想利用github-pages服务做内容服务器，将自己注册的域名指向github-pages。这样我就拥有了自己的blog系统，且功能、风格完全可以由自己控制，并且还自带git版本管理，真是超爽。&lt;/p&gt;

&lt;h3 id=&quot;域名申请和域名设置&quot;&gt;域名申请和域名设置&lt;/h3&gt;

&lt;p&gt;给自己孩子起名字要先想好一个容易记、有含义的汉字组合，然后去办理出生证明的地方注册。注册网络上的域名也是一样，先想好一个好名字(当然要符合域名命名规范喽)，然后去域名服务商那里注册。国外、国内的域名服务商都很多，鉴于目前我服务的人群大部分是国内技术人员，所以我选择了国内aliyun旗下的&lt;a href=&quot;https://wanwang.aliyun.com/&quot; title=&quot;万网---阿里云旗下产品&quot;&gt;wanwang&lt;/a&gt;。在阿里云—万网上注册域名的流程这里就不再赘述了。这里顺便说一下域名和内容服务在国内的一些相关政策。域名的话，需要实名认证，我的域名是个人属性，因此走的是个人实名认证。网站内容服务(提供网站服务的主机在国内)需要进行备案，且要求域名持有者名称与备案主体名称一致，并完成域名实名认证。而我的网站内容服务使用的github-pages做的内容服务，他们的服务器在国外，因此无需进行网站备案，只需要做域名实名认证就好了。域名实名认证方法见&lt;a href=&quot;https://help.aliyun.com/knowledge_detail/35881.html?spm=a2c4e.11155515.0.0.xDePmY&quot; title=&quot;阿里云域名实名制认证&quot;&gt;域名实名制认证&lt;/a&gt;。我申请的域名是&lt;a href=&quot;https://www.bahutou.cn&quot; title=&quot;bahutou's blog&quot;&gt;bahutou.cn&lt;/a&gt;有了域名之后，怎么设置才能实现通过域名访问到自己的github-pages呐？以我的域名和github为例来进行说明具体的设置方法。先说一下github-pages提供的服务，github-pages提供两种基本的web服务：&lt;strong&gt;User, Organization&lt;/strong&gt; and &lt;strong&gt;Project&lt;/strong&gt; Pages 。一个是以个人或者组织为主，一个是以项目为主。我使用的是User Pages这种模式。这种方式的使用方法见&lt;a href=&quot;https://pages.github.com/&quot; title=&quot;GitHub Pages&quot;&gt;GitHub Pages&lt;/a&gt;。我的github个人主页地址&lt;a href=&quot;https://zhanglianpin.github.io&quot; title=&quot;zhanglianpin.github.io&quot;&gt;zhanglianpin.github.io&lt;/a&gt;。下一个问题就是如何将我申请的域名指向到我的github-pages上。不同的需求操作方法也不一样，我的需求是域名&lt;a href=&quot;https://www.bahutou.cn&quot; title=&quot;bahutou's blog&quot;&gt;www.bahutou.cn&lt;/a&gt;和&lt;a href=&quot;https://www.bahutou.cn&quot; title=&quot;bahutou's blog&quot;&gt;bahutou.cn&lt;/a&gt;都重定向到&lt;a href=&quot;https://zhanglianpin.github.io&quot; title=&quot;zhanglianpin.github.io&quot;&gt;zhanglianpin.github.io&lt;/a&gt;。设置方法见 &lt;a href=&quot;https://help.github.com/articles/using-a-custom-domain-with-github-pages/&quot; title=&quot;Using a custom domain with GitHub Pages&quot;&gt;Using a custom domain with GitHub Pages&lt;/a&gt;。我的具体设置过程是这样的。首先设置我的github-pages：zhanglianpin/zhanglianpin.github.io—&amp;gt;setting—&amp;gt;GitHub Pages—&amp;gt;Custom domain。我设置的值是：www.bahutou.cn。官方设置步骤见&lt;a href=&quot;https://help.github.com/articles/adding-or-removing-a-custom-domain-for-your-github-pages-site/&quot; title=&quot;Adding or removing a custom domain for your GitHub Pages site&quot;&gt;Adding or removing a custom domain for your GitHub Pages site&lt;/a&gt;。有图有真相：
&lt;img src=&quot;/images/posts/2018-02-27-build-blog-using-jekyll-and-github-pages/github-pages-using-Custom-domains.png&quot; alt=&quot;github-pages-using-Custom domains &quot; title=&quot;Custom domains&quot; /&gt;
然后我在我的aliyun里设置DNS，根据github-pages里面的说明，需要同时设置一条A记录和一条CNAME记录。其中A记录负责解析&lt;a href=&quot;https://www.bahutou.cn&quot; title=&quot;bahutou's blog&quot;&gt;bahutou.cn&lt;/a&gt;这个Domain，CNAME负责解析&lt;a href=&quot;https://www.bahutou.cn&quot; title=&quot;bahutou's blog&quot;&gt;www.bahutou.cn&lt;/a&gt;这个Sub-domain。&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;A @ 151.101.229.147&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;CNAME	www zhanglianpin.github.io&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;还是上张图吧。
&lt;img src=&quot;/images/posts/2018-02-27-build-blog-using-jekyll-and-github-pages/aliyun-dns-setting.png&quot; alt=&quot;aliyun-dns-setting &quot; title=&quot;DNS-setting&quot; /&gt;
通过上述的设置，我申请的域名指向了我的github上的github-pages。可以通过我的域名访问我自己的blog喽，还有点小激动呐。&lt;/p&gt;

&lt;h3 id=&quot;github-pages和jekyll介绍&quot;&gt;github-pages和Jekyll介绍&lt;/h3&gt;

&lt;p&gt;github-pages是github提供的Web服务，为注册github的用户、组织或者项目提供Web服务。其主要用于用户、组织宣传，或者项目介绍等，当然是用github-pages提供的服务制作自己的blog系统也是很不错的选择。这么做也是符合github分享价值观的，blog分享也是一种值得鼓励的分享行为。专业的介绍在这里&lt;a href=&quot;https://help.github.com/articles/what-is-github-pages/&quot; title=&quot;What is GitHub Pages?&quot;&gt;What is GitHub Pages?&lt;/a&gt;. 但是，github-pages提供的Web服务是static的，不支持动态执行环境(比如:PHP、Ruby、Python)和数据库服务。那有些小伙伴就有疑惑了，难道我的每一篇都要使用html+js手动编写吗？NO,NO，我们有Jekyll，Jekyll是一个简单的，适合博客的（blog aware），静态网站生成器。输入一个模板目录（代表网站的原始形态），经过Texitile和Liquid转换，输出一个完全静态的网站。你可以发布在任何你喜爱的服务器上。Jekyll 也可以运行在 GitHub Page 上，也就是说，你可以使用 GitHub 的服务来搭建你的项目页面、博客或者网站，而且是完全免费的。使用Jekyll构建的网站源目录上传到github指定的仓库中，github就会自动生成静态页面，非常方便。Jekyll作者（也是GitHub的共同创始人） Tom Preston-Werner，在github上的名字叫&lt;a href=&quot;https://github.com/mojombo&quot; title=&quot;mojombo&quot;&gt;mojombo&lt;/a&gt;。还是忍不住再提一次它的&lt;a href=&quot;http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html&quot; title=&quot;Blogging Like a Hacker&quot;&gt;Blogging Like a Hacker&lt;/a&gt;，值得一读。&lt;/p&gt;

&lt;h3 id=&quot;有关jekyll&quot;&gt;有关Jekyll&lt;/h3&gt;
&lt;h4 id=&quot;jekyll&quot;&gt;Jekyll&lt;/h4&gt;

&lt;p&gt;Jekyll 是一个简单的博客形态的静态站点生产机器。它有一个模版目录，其中包含原始文本格式的文档，通过一个转换器（如 Markdown）和我们的 Liquid 渲染器转化成一个完整的可发布的静态网站，你可以发布在任何你喜爱的服务器上。Jekyll 也可以运行在 GitHub Page 上，也就是说，你可以使用 GitHub 的服务来搭建你的项目页面、博客或者网站，而且是完全免费的。&lt;/p&gt;

&lt;p&gt;Jekyll is a simple, blog-aware, static site generator perfect for personal, project, or organization sites. Think of it like a file-based CMS, without all the complexity. Jekyll takes your content, renders Markdown and Liquid templates, and spits out a complete, static website ready to be served by Apache, Nginx or another web server. Jekyll is the engine behind GitHub Pages, which you can use to host sites right from your GitHub repositories.&lt;/p&gt;

&lt;p&gt;官方网站&lt;a href=&quot;https://jekyllrb.com/&quot; title=&quot;jekyllrb&quot;&gt;jekyllrb&lt;/a&gt;、github地址&lt;a href=&quot;https://github.com/jekyll/jekyll&quot; title=&quot;github-jekyll&quot;&gt;jekyll&lt;/a&gt;。&lt;/p&gt;

&lt;h4 id=&quot;jekyll的本地环境搭建&quot;&gt;Jekyll的本地环境搭建&lt;/h4&gt;

&lt;p&gt;搭建Jekyll本地执行环境的目的是本地预览效果。在本地编辑好文件后，在本地可以看到效果，这样只需要一次git push就可以了。如果本地不安装jekyll，github pages中一旦出现显示问题，就需要不断地修改，并不断git push提交修改。&lt;/p&gt;

&lt;p&gt;基本思路：从技术角度来看，Jekyll是使用Ruby语言编写的一个软件，因此要运行Jekyll需要首先安装Ruby执行环境。Jekyll作为一个使用Ruby语言开发的软件一定有其方便开发者和使用者的发布方式和安装方式。Ruby软件包管理软件叫&lt;a href=&quot;https://rubygems.org/&quot; title=&quot;RubyGems&quot;&gt;RubyGems&lt;/a&gt;，它可以辅助你发布或者安装用Ruby语言写的软件，而且能自动处理依赖关系。为了方便我们安装上这个Gem。
依赖：&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.ruby-lang.org/en/downloads/&quot; title=&quot;Ruby&quot;&gt;Ruby&lt;/a&gt;（including development headers, Jekyll 2 需要 v1.9.3 及以上版本，Jekyll 3 需要 v2 及以上版本）&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rubygems.org/&quot; title=&quot;RubyGems&quot;&gt;RubyGems&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Linux, Un ix, or Mac OS X&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot; title=&quot;NodeJS&quot;&gt;NodeJS&lt;/a&gt;, 或其他 JavaScript 运行环境（Jekyll 2 或更早版本需要 CoffeeScript 支持）。&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.python.org/downloads/&quot; title=&quot;Python 2.7&quot;&gt;Python-2.7&lt;/a&gt; （Jekyll 2 或更早版本）&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;上述依赖安装完毕之后，就可以安装Jekyll了。
我的开发环境使用的是Win10下面的Bash on Ubuntu on Windows，一个windows仿真ubuntu的虚拟环境，不用安装Vmware虚拟机软件了，而且网络、文件都可以和Win10共享，十分方便。&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; You must have &lt;a href=&quot;https://msdn.microsoft.com/en-us/commandline/wsl/about&quot;&gt;Bash on Ubuntu on Windows&lt;/a&gt; enabled.&lt;/p&gt;

&lt;p&gt;First let’s make sure all our packages / repositories are up to date. Open a new Command Prompt instance, and type the following:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Your Command Prompt instance should now be a Bash instance. Now we must update our repo lists and packages.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get upgrade &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now we can install Ruby. To do this we will use a repository from &lt;a href=&quot;https://www.brightbox.com/docs/ruby/ubuntu/&quot;&gt;BrightBox&lt;/a&gt;, which hosts optimized versions of Ruby for Ubuntu.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-add-repository ppa:brightbox/ruby-ng
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;ruby2.3 ruby2.3-dev build-essential dh-autoreconf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next let’s update our Ruby gems:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;gem update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now all that is left to do is install Jekyll.&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;gem &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;jekyll bundler
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check if Jekyll installed properly by running:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jekyll &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;And that’s it!&lt;/strong&gt;&lt;/p&gt;

&lt;h4 id=&quot;使用jekyll创建blog系统&quot;&gt;使用Jekyll创建blog系统&lt;/h4&gt;

&lt;p&gt;To start a new project named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;my_blog&lt;/code&gt;, just run:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;jekyll new my_blog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You can make sure time management is working properly by inspecting your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_posts&lt;/code&gt; folder. You should see a markdown file with the current date in the filename.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Bash on Ubuntu on Windows is still under development, so you may run into issues.&lt;/p&gt;

&lt;h4 id=&quot;jekyll目录结构和解释&quot;&gt;Jekyll目录结构和解释&lt;/h4&gt;
&lt;p&gt;Jekyll 的核心其实是一个文本转换引擎。它的概念其实就是：你用你最喜欢的标记语言来写文章，可以是 Markdown, 也可以是 Textile, 或者就是简单的 HTML, 然后 Jekyll 就会帮你套入一个或一系列的布局中。在整个过程中你可以设置 URL 路径，你的文本在布局中的显示样式等等。这些都可以通过纯文本编辑来实现，最终生成的静态页面就是你的成品了。&lt;/p&gt;

&lt;p&gt;一个基本的 Jekyll 网站的目录结构一般是像这样的：&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
├── _config.yml
├── _drafts
|   ├── begin-with-the-crazy-ideas.textile
|   └── on-simplicity-in-technology.markdown
├── _includes
|   ├── footer.html
|   └── header.html
├── _layouts
|   ├── default.html
|   └── post.html
├── _posts
|   ├── 2007-10-29-why-every-programmer-should-play-nethack.textile
|   └── 2009-04-26-barcamp-boston-4-roundup.textile
├── _site
├── .jekyll-metadata
└── index.html&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;来看看这些都有什么用：&lt;/p&gt;

&lt;div class=&quot;mobile-side-scroller&quot;&gt;
&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;文件 / 目录&lt;/th&gt;
      &lt;th&gt;描述&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;_config.yml&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          保存配置数据。很多配置选项都可以直接在命令行中进行设置，但是如果你把那些配置写在这儿，你就不用非要去记住那些命令了。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;_drafts&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          drafts（草稿）是未发布的文章。这些文件的格式中都没有 &lt;code&gt;title.MARKUP&lt;/code&gt; 数据。学习如何使用草稿.

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;_includes&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          你可以加载这些包含部分到你的布局或者文章中以方便重用。可以用这个标签
          &lt;code&gt;{% include file.ext %}&lt;/code&gt;
          来把文件 &lt;code&gt;_includes/file.ext&lt;/code&gt; 包含进来。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;_layouts&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          layouts（布局）是包裹在文章外部的模板。布局可以在 YAML 头信息中根据不同文章进行选择。
          这将在下一个部分进行介绍。标签
          &lt;code&gt;{{ content }}&lt;/code&gt;
          可以将content插入页面中。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;_posts&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          这里放的就是你的文章了。文件格式很重要，必须要符合:
          &lt;code&gt;YEAR-MONTH-DAY-title.MARKUP&lt;/code&gt;。
          永久链接可以在文章中自己定制，但是数据和标记语言都是根据文件名来确定的。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;_data&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          格式化好的网站数据应放在这里。jekyll 的引擎会自动加载在该目录下所有的 yaml 文件（后缀是 &lt;code&gt;.yml&lt;/code&gt;, &lt;code&gt;.yaml&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt; 或者 &lt;code&gt;.csv&lt;/code&gt; ）。这些文件可以经由 ｀site.data｀ 访问。如果有一个 &lt;code&gt;members.yml&lt;/code&gt; 文件在该目录下，你就可以通过 &lt;code&gt;site.data.members&lt;/code&gt; 获取该文件的内容。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;_site&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          一旦 Jekyll 完成转换，就会将生成的页面放在这里（默认）。最好将这个目录放进你的 &lt;code&gt;.gitignore&lt;/code&gt; 文件中。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
     &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;.jekyll-metadata&lt;/code&gt;&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          该文件帮助 Jekyll 跟踪哪些文件从上次建立站点开始到现在没有被修改，哪些文件需要在下一次站点建立时重新生成。该文件不会被包含在生成的站点中。将它加入到你的 &lt;code&gt;.gitignore&lt;/code&gt; 文件可能是一个好注意。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;&lt;code&gt;index.html&lt;/code&gt; and other HTML, Markdown, Textile files&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          如果这些文件中包含 YAML 头信息部分，Jekyll 就会自动将它们进行转换。当然，其他的如 &lt;code&gt;.html&lt;/code&gt;, &lt;code&gt;.markdown&lt;/code&gt;, &lt;code&gt;.md&lt;/code&gt;, 或者 &lt;code&gt;.textile&lt;/code&gt; 等在你的站点根目录下或者不是以上提到的目录中的文件也会被转换。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;
        &lt;p&gt;Other Files/Folders&lt;/p&gt;
      &lt;/td&gt;
      &lt;td&gt;
        &lt;p&gt;

          其他一些未被提及的目录和文件如
          &lt;code&gt;css&lt;/code&gt; 还有 &lt;code&gt;images&lt;/code&gt; 文件夹，
          &lt;code&gt;favicon.ico&lt;/code&gt; 等文件都将被完全拷贝到生成的 site 中。这里有一些使用 &lt;a href=&quot;https://github.com/jekyll/jekyll/wiki/Sites&quot;&gt;Jekyll 的站点&lt;/a&gt;  ，如果你感兴趣就来看看吧。

        &lt;/p&gt;
      &lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;

&lt;h4 id=&quot;使用jekyll编写blog&quot;&gt;使用Jekyll编写blog&lt;/h4&gt;

&lt;p&gt;编写的blog动态内容要放到_post中，编写blog的markdown文件名的命名有些学问。必须满足如下的形式：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;year-month-day-***-***-***.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;前面是年月日、后面是文件名称，各个单词之间使用”-“分割。&lt;/p&gt;

&lt;p&gt;文件内容有个header：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;---
layout: post
title: 使用Jekyll和github-pages搭建个人blog系统
categories: Jekyll&amp;amp;&amp;amp;github-pages
description: 描述使用Jekyll和jithub-pages搭建个人博客的基本思路和方法
keywords: Jekyll github-pages
---
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;有这个header的文件才会被Jekyll解释其中的Liquid模板文件，否则Jekyll就当做是普通文件，直接转换成静态的HTML文件了。在这里主要定义一些一篇文章需要的名称、分类、关键字等等内容。其实编写语法是和YAML一样的，只不过放到了开头并用加上了特殊标识而已。在这里吗定义的变量，使用Liquid就可以使用。比如：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; {{ page.title }}  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;发布到github-pages&quot;&gt;发布到github-pages&lt;/h4&gt;

&lt;p&gt;将本地生成的网站目录结构上传到github仓库的master分支，我的用户仓库是zhanglianpin.github.io。&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git push origin master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;稍等1—2分钟，github-pages会自动将上传的Jekyll网站框架和内容生成静态网站内容，然后通过浏览器就可以访问网站内容了。&lt;/p&gt;

&lt;h4 id=&quot;gem和bundler&quot;&gt;Gem和bundler&lt;/h4&gt;

&lt;p&gt;刚接触Ruby，对Gem和bundler之间的关系和区别有些疑惑。Gem比较好理解，就是一个软件管理器(安装、更新、卸载软件)，就像ubuntu里的apt，CentOS里的yum。那这个bundler又是干什么用的呐？简单的说它为一个具体的Project提供一个统一的运行环境，处理各种包的依赖关系，确保兼容性。一个Project也许会用到不同的Gem包，这些包之间的依赖关系和版本号如果人工管理的话还是挺没意思的，快乐的程序员们怎么会允许这样的事情发生，bundler诞生了。它使用一个Gemfile文件自动维护各个包的依赖关系。具体用法见&lt;a href=&quot;http://bundler.io/&quot; title=&quot;bundler&quot;&gt;bundler&lt;/a&gt;，&lt;a href=&quot;https://github.com/bundler/bundler&quot; title=&quot;github-bundler&quot;&gt;github-bundler&lt;/a&gt;。Jekyll这个项目默认使用bundler作为项目各个包的依赖关系处理。&lt;/p&gt;

&lt;h4 id=&quot;liquid&quot;&gt;Liquid&lt;/h4&gt;

&lt;p&gt;Liquid是一个模板语言，支持基本的变量，逻辑控制等等基本的功能。使用Ruby语言编写，Jekyll中就是使用Liquid这种模块语言做页面的动态部分的处理。项目主页&lt;a href=&quot;https://shopify.github.io/liquid/&quot; title=&quot;liquid&quot;&gt;Liquid&lt;/a&gt;，github项目地址&lt;a href=&quot;https://github.com/Shopify/liquid&quot; title=&quot;github-liquid&quot;&gt;github-liquid&lt;/a&gt;。打开帮助文档，有一点编程基础的人花十来分钟就能掌握了，十分精简的模板语言。&lt;/p&gt;

&lt;h4 id=&quot;yaml&quot;&gt;YAML&lt;/h4&gt;

&lt;p&gt;YAML 是一种格式化标记语言。官方解释：YAML (/ˈjæməl/, rhymes with camel) is a human-readable data serialization language. It is commonly used for configuration files, but could be used in many applications where data is being stored (e.g. debugging output) or transmitted (e.g. document headers).官方网址&lt;a href=&quot;http://yaml.org/&quot;&gt;yaml&lt;/a&gt;。&lt;/p&gt;

&lt;h4 id=&quot;blog动态语言和静态语言&quot;&gt;blog动态语言和静态语言&lt;/h4&gt;

&lt;p&gt;前面一直在说Jekyll是一个静态网站生成器。那这个Jekyll肯定支持一部分动态特性，要是只支持静态标记语言那就没意思了。blog的主要核心部分：一是支持好的编写blog内容的方式，像Markdown、Textile等轻量级标记语言; 二是支持一些动态特性，比如Tag、文章目录等。静态内容支持的语言有：Markdown（或 Textile）、Liquid 和 HTML &amp;amp; CSS。动态语言主要是模块语言Liquid(可以使用YAML的格式化数据)。&lt;/p&gt;

&lt;h3 id=&quot;使用开源的jekylltheme快速搭建博客&quot;&gt;使用开源的Jekyll、Theme快速搭建博客&lt;/h3&gt;

&lt;p&gt;github上有特别多的使用Jekyll&amp;amp;&amp;amp;github-pages搭建的blog系统，且都是开源的。我使用的是&lt;a href=&quot;https://github.com/mzlogin/mzlogin.github.io&quot;&gt;mzlogin/mzlogin.github.io&lt;/a&gt; 。&lt;/p&gt;

&lt;p&gt;Fork 指南&lt;/p&gt;

&lt;p&gt;Fork 本项目之后，还需要做一些事情才能让你的页面「正确」跑起来。&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;正确设置项目名称与分支。&lt;/p&gt;

    &lt;p&gt;按照 GitHub Pages 的规定，名称为 &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;username.github.io&lt;/code&gt; 的项目的 master 分支，或者其它名称的项目的 gh-pages 分支可以自动生成 GitHub Pages 页面。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;修改域名。&lt;/p&gt;

    &lt;p&gt;如果你需要绑定自己的域名，那么修改 CNAME 文件的内容；如果不需要绑定自己的域名，那么删掉 CNAME 文件。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;修改配置。&lt;/p&gt;

    &lt;p&gt;网站的配置基本都集中在 _config.yml 文件中，将其中与个人信息相关的部分替换成你自己的，比如网站的 url、title、subtitle 和第三方评论模块的配置等。&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;评论模块：&lt;/strong&gt; 目前支持 disqus、gitment 和 gitalk，选用其中一种就可以了，推荐使用 gitalk。它们各自的配置指南链接在 _config.yml 文件的 Comments 一节里都贴出来了。&lt;/p&gt;

    &lt;p&gt;&lt;strong&gt;注意：&lt;/strong&gt; 如果使用 disqus，因为 disqus 处理用户名与域名白名单的策略存在缺陷，请一定将 disqus.username 修改成你自己的，否则请将该字段留空。我对该缺陷的记录见 &lt;a href=&quot;https://github.com/topics/github-pages&quot; title=&quot;github-pages&quot;&gt;Issues#2&lt;/a&gt;。&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;删除我的文章与图片。&lt;/p&gt;

    &lt;p&gt;如下文件夹中除了 template.md 文件外，都可以全部删除，然后添加你自己的内容。&lt;/p&gt;

    &lt;ul&gt;
      &lt;li&gt;_posts 文件夹中是我已发布的博客文章。&lt;/li&gt;
      &lt;li&gt;_drafts 文件夹中是我尚未发布的博客文章。&lt;/li&gt;
      &lt;li&gt;_wiki 文件夹中是我已发布的 wiki 页面。&lt;/li&gt;
      &lt;li&gt;images 文件夹中是我的文章和页面里使用的图片。&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;修改「关于」页面。&lt;/p&gt;

    &lt;p&gt;pages/about.md 文件内容对应网站的「关于」页面，里面的内容多为个人相关，将它们替换成你自己的信息，包括 _data 目录下的 skills.yml 和 social.yml 文件里的数据。&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h4 id=&quot;评论系统使用gitalk&quot;&gt;评论系统使用gitalk&lt;/h4&gt;

&lt;p&gt;Jekyll的工作模式意味着像评论这样的系统必须借助第三方评论插件，我选择使用了&lt;a href=&quot;https://github.com/gitalk/gitalk/&quot;&gt;gitalk&lt;/a&gt;，一个使用github自带的issue系统做的评论插件，不过只支持github用户登录、评论。还好吧，现在没有github账号的程序员也不多了。使用gitalk涉及到两个问题：1，自己的blog如何加载gitalk并显示？2，如何授权使用github用户登录自己的blog评论系统进行评论？&lt;/p&gt;

&lt;p&gt;第一个问题比较简单，gitalk官网的install说明里说的比较清楚，使用links方式进行从外网加载到本地，在本地执行简单逻辑功能。&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;link&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;stylesheet&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://unpkg.com/gitalk/dist/gitalk.css&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://unpkg.com/gitalk/dist/gitalk.min.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/script&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;融合到Jekyll中使用的是&lt;a href=&quot;https://github.com/zhanglianpin/zhanglianpin.github.io/blob/master/_includes/comments.html&quot;&gt;_inclus/comments.html&lt;/a&gt;这个文件。&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gitalk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Gitalk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;page.url&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;clientID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;clientID&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;clientSecret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;clientSecret&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;owner &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gitment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;perPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;初始化gitalk时需要一些参数，因为这些参数不用的blog需要使用自己的github账号等一些信息，因此是变量。这些参数通过Liquid模板语言提取出来作为了变量放在了格式化数据YAML文件&lt;a href=&quot;https://github.com/zhanglianpin/zhanglianpin.github.io/blob/master/_config.yml&quot;&gt;_config.yml&lt;/a&gt;中。具体参数如下：&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;# https://github.com/gitalk/gitalk#install
gitalk:
    owner: zhanglianpin
    repo: blog-comments
    clientID: decb151c48f4a658ec81
    clientSecret: c2a95f788d773b3a25b68d0a3f25b78bedc80370
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;参考liquid语法很容易知道，引用上述变量的方法：&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gitalk&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Gitalk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{{ page.url }}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;clientID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{{ site.gitalk.clientID }}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;clientSecret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{{ site.gitalk.clientSecret }}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;repo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{{ site.gitalk.repo }}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{{ site.gitalk.owner }}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{{ site.gitalk.owner }}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;labels&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gitment&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
            &lt;span class=&quot;na&quot;&gt;perPage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;gitalk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;gitalk-container&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;简单说明一下上述参数，前面说了gitalk使用的是github project的issue功能实现的，因此上述参数大部分都和project的issue有关系。
repo指定那个github 仓库作为存储issue的地方，我的仓库是：&lt;a href=&quot;https://github.com/zhanglianpin/blog-comments&quot;&gt;blog-comments&lt;/a&gt;。owner和admin都是github的账号，我的是zhanglianpin。id是在github上创建issue时使用的一个label，github的issue中label是有长度限制的(50个字符以内)。我们这里使用的page.url，因此建议发布博客时文件名不要太长。&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;发布博客时文件名不要超过40个字符。&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;clientID和clientSecret是用户授权github账号登陆第三方网站使用的。就像我现在的blog系统，如果在网站上点击使用github登陆按钮会跳转到授权页面，让你授权github账号登陆本blog的评论系统。
&lt;img src=&quot;/images/posts/2018-02-27-build-blog-using-jekyll-and-github-pages/gitalk-login.png&quot; alt=&quot;gitalk-login&quot; title=&quot;gitalk-login&quot; /&gt;&lt;/p&gt;

&lt;p&gt;这个clientID和clientSecret是你自己在github申请的。具体的申请步骤见&lt;a href=&quot;https://developer.github.com/apps/building-oauth-apps/creating-an-oauth-app/&quot;&gt;Creating an OAuth App&lt;/a&gt;。
具体填写内容可能比较关键，以我的blog为例，我写的参数如下：&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/2018-02-27-build-blog-using-jekyll-and-github-pages/Creating-an-OAuth-App.png&quot; alt=&quot;Creating-an-OAuth-App&quot; title=&quot;Creating-an-OAuth-App&quot; /&gt;&lt;/p&gt;

&lt;h4 id=&quot;搜索使用js库&quot;&gt;搜索使用JS库&lt;/h4&gt;

&lt;p&gt;搜索使用的也是JS库的方式，只能搜索文章标题。关于搜索的代码还没分析，分析之后再分享，权当了解一下JavaScript语言了。&lt;/p&gt;

&lt;h4 id=&quot;数学公式支持使用js库-mathjax&quot;&gt;数学公式支持使用JS库-MathJax&lt;/h4&gt;

&lt;p&gt;Markdown默认没有数学公式的支持，当然需要第三方插件，最简单的方式当然是外部JS库喽。使用MathJax的方法很简单：&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mathjax&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
		&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;text/javascript&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://basis-learning.github.io/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/script&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;	&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;endif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;我把这个外部js库放在了Jekyll的&lt;a href=&quot;https://github.com/zhanglianpin/zhanglianpin.github.io/blob/master/_includes/foot.html&quot;&gt;_inclus/foot.html&lt;/a&gt;,在发布blog时的header中设置page.mathjax就可以使用mathjax这个js库，没有数学公式的blog不设置此选项，也防止了没有数学公式的blog加载mathjax。&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;layout&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;post&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;聊聊量子计算机那些事&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;categories&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;QuantumComputer&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;聊聊量子计算机那些事&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;keywords&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;量子计算机 量子算法&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;mathjax&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;访问统计和字数统计等功能&quot;&gt;访问统计和字数统计等功能&lt;/h4&gt;

&lt;p&gt;网站访问统计使用的是&lt;a href=&quot;https://analytics.google.com&quot;&gt;Google analytics&lt;/a&gt;。打开网站，使用Google账号登陆，然后新建网络媒体资源。
&lt;img src=&quot;/images/posts/2018-02-27-build-blog-using-jekyll-and-github-pages/Google-Analytics-new.png&quot; alt=&quot;Google-analytics-new&quot; title=&quot;Google-analytics-new&quot; /&gt;
成功后会生成一个USER-id，然后利用JS代码将访问情况上传到Google analytics center，你可以登陆 Google Analytics 进行查看分析访问情况。&lt;/p&gt;

&lt;p&gt;申请的user-id，放到_config.yml中作为变量，在_includes/foot.html中添加如下代码：&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;div&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;display:none&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GoogleAnalyticsObject&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;||&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[]).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)},&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;g&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parentNode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;insertBefore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;})(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;https://www.google-analytics.com/analytics.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;{{ site.google.analytics_id }}&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;ga&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;pageview&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

      &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/script&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/div&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;登陆Google analytics就可以查看网站访问统计信息，功能很强大的。
&lt;img src=&quot;/images/posts/2018-02-27-build-blog-using-jekyll-and-github-pages/Google-Analytics-result.png&quot; alt=&quot;Google-analytics-result&quot; title=&quot;Google-analytics-result&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;引用资源&quot;&gt;引用资源&lt;/h3&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://jekyllrb.com/&quot;&gt;jekyll&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.ruby-lang.org/en/&quot;&gt;Ruby&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;liquid&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://yaml.org/&quot;&gt;yaml&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rubygems.org/&quot;&gt;RubyGems&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://bundler.io/&quot;&gt;bundler&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/gitalk/gitalk/&quot;&gt;Gitalk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.mathjax.org/&quot;&gt;MathJax&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jekyll/jekyll/wiki/Sites&quot;&gt;使用Jekyll&amp;amp;&amp;amp;github-pages搭建的blog列表&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content><author><name>Linc Zhang</name></author><summary type="html">朋友，你是否也想拥有一个自主可控的blog系统？先看看我自己的博客：bahutou’s blog。现在就可以用很低的成本实现，这篇文章就详细描述了如何利用现有的开源技术(Jekyll github-pages)搭建属于自己的blog系统。开始行动吧，小伙伴！</summary></entry></feed>