2remove-std.html 17.9 KB
Newer Older
Y
Yifan Wu 已提交
1 2 3


<!DOCTYPE html>
Y
Yifan Wu 已提交
4 5
<!--[if IE 8]><html class="no-js lt-ie9" lang="zh-CN" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="zh-CN" > <!--<![endif]-->
Y
Yifan Wu 已提交
6 7 8 9 10
<head>
  <meta charset="utf-8">
  
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  
Y
Yifan Wu 已提交
11
  <title>移除标准库依赖 &mdash; rCore-Tutorial-Book-v3 0.1 文档</title>
Y
Yifan Wu 已提交
12 13 14 15 16 17 18 19
  

  
  
  
  

  
Y
Yifan Wu 已提交
20
  <script type="text/javascript" src="../_static/js/modernizr.min.js"></script>
Y
Yifan Wu 已提交
21 22 23 24 25 26 27
  
    
      <script type="text/javascript" id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
        <script src="../_static/jquery.js"></script>
        <script src="../_static/underscore.js"></script>
        <script src="../_static/doctools.js"></script>
        <script src="../_static/language_data.js"></script>
Y
Yifan Wu 已提交
28
        <script src="../_static/translations.js"></script>
Y
Yifan Wu 已提交
29 30 31 32 33
        <script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
    
    <script type="text/javascript" src="../_static/js/theme.js"></script>

    
Y
Yifan Wu 已提交
34 35 36 37

  
  <link rel="stylesheet" href="../_static/css/theme.css" type="text/css" />
  <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
Y
Yifan Wu 已提交
38 39
    <link rel="index" title="索引" href="../genindex.html" />
    <link rel="search" title="搜索" href="../search.html" />
Y
Yifan Wu 已提交
40
    <link rel="next" title="重建最小化运行时" href="3minimal-rt.html" />
Y
Yifan Wu 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54
    <link rel="prev" title="应用程序运行环境与平台支持" href="1app-ee-platform.html" /> 
</head>

<body class="wy-body-for-nav">

   
  <div class="wy-grid-for-nav">
    
    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
      <div class="wy-side-scroll">
        <div class="wy-side-nav-search" >
          

          
Y
Yifan Wu 已提交
55
            <a href="../index.html" class="icon icon-home"> rCore-Tutorial-Book-v3
Y
Yifan Wu 已提交
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
          

          
          </a>

          
            
            
          

          
<div role="search">
  <form id="rtd-search-form" class="wy-form" action="../search.html" method="get">
    <input type="text" name="q" placeholder="Search docs" />
    <input type="hidden" name="check_keywords" value="yes" />
    <input type="hidden" name="area" value="default" />
  </form>
</div>

          
        </div>

        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="main navigation">
          
            
            
              
            
            
              <p class="caption"><span class="caption-text">正文</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../quickstart.html">快速上手</a></li>
88
<li class="toctree-l1 current"><a class="reference internal" href="index.html">第一章:构建运行 RV64 裸机程序</a><ul class="current">
Y
Yifan Wu 已提交
89 90 91 92 93 94 95
<li class="toctree-l2"><a class="reference internal" href="1app-ee-platform.html">应用程序运行环境与平台支持</a></li>
<li class="toctree-l2 current"><a class="current reference internal" href="#">移除标准库依赖</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#println">移除 println! 宏</a></li>
<li class="toctree-l3"><a class="reference internal" href="#panic-handler">提供语义项 panic_handler</a></li>
<li class="toctree-l3"><a class="reference internal" href="#main">移除 main 函数</a></li>
</ul>
</li>
Y
Yifan Wu 已提交
96
<li class="toctree-l2"><a class="reference internal" href="3minimal-rt.html">重建最小化运行时</a></li>
97
<li class="toctree-l2"><a class="reference internal" href="4load-manually.html">手动加载、运行应用程序</a></li>
Y
Yifan Wu 已提交
98
<li class="toctree-l2"><a class="reference internal" href="5sbi-print.html">格式化输出</a></li>
Y
Yifan Wu 已提交
99
<li class="toctree-l2"><a class="reference internal" href="6practice.html">练习一</a></li>
Y
Yifan Wu 已提交
100 101
</ul>
</li>
Y
Yifan Wu 已提交
102
<li class="toctree-l1"><a class="reference internal" href="../chapter2/index.html">第二章:系统调用</a></li>
Y
Yifan Wu 已提交
103 104 105 106
</ul>
<p class="caption"><span class="caption-text">开发注记</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../rest-example.html">reStructuredText 基本语法</a></li>
Y
Yifan Wu 已提交
107
<li class="toctree-l1"><a class="reference internal" href="../collaboration.html">项目协作</a></li>
Y
Yifan Wu 已提交
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
</ul>

            
          
        </div>
      </div>
    </nav>

    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">

      
      <nav class="wy-nav-top" aria-label="top navigation">
        
          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
          <a href="../index.html">rCore-Tutorial-Book-v3</a>
        
      </nav>


      <div class="wy-nav-content">
        
        <div class="rst-content">
        
          















<div role="navigation" aria-label="breadcrumbs navigation">

  <ul class="wy-breadcrumbs">
    
Y
Yifan Wu 已提交
151
      <li><a href="../index.html">Docs</a> &raquo;</li>
Y
Yifan Wu 已提交
152
        
153
          <li><a href="index.html">第一章:构建运行 RV64 裸机程序</a> &raquo;</li>
Y
Yifan Wu 已提交
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
        
      <li>移除标准库依赖</li>
    
    
      <li class="wy-breadcrumbs-aside">
        
            
            <a href="../_sources/chapter1/2remove-std.rst.txt" rel="nofollow"> View page source</a>
          
        
      </li>
    
  </ul>

  
  <hr/>
</div>
          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
           <div itemprop="articleBody">
            
  <div class="section" id="id1">
Y
Yifan Wu 已提交
175
<h1>移除标准库依赖<a class="headerlink" href="#id1" title="永久链接至标题"></a></h1>
Y
Yifan Wu 已提交
176 177 178 179
<div class="toctree-wrapper compound">
</div>
<p>本节我们尝试移除之前的 <code class="docutils literal notranslate"><span class="pre">Hello</span> <span class="pre">world!</span></code> 程序对于标准库的依赖,使得它能够编译到裸机平台 RV64GC 上。</p>
<p>我们首先在 <code class="docutils literal notranslate"><span class="pre">os</span></code> 目录下新建 <code class="docutils literal notranslate"><span class="pre">.cargo</span></code> 目录,并在这个目录下创建 <code class="docutils literal notranslate"><span class="pre">config</span></code> 文件,并在里面输入如下内容:</p>
180 181
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">//</span> <span class="n">os</span><span class="o">/.</span><span class="n">cargo</span><span class="o">/</span><span class="n">config</span>
<span class="p">[</span><span class="n">build</span><span class="p">]</span>
Y
Yifan Wu 已提交
182 183 184 185 186 187 188 189
<span class="n">target</span> <span class="o">=</span> <span class="s2">&quot;riscv64gc-unknown-none-elf&quot;</span>
</pre></div>
</div>
<p>这会对于 Cargo 工具在 os 目录下的行为进行调整:现在默认会使用 riscv64gc 作为目标平台而不是原先的默认 x86_64-unknown-linux-gnu。
事实上,这是一种编译器运行所在的平台与编译器生成可执行文件的目标平台不同(分别是后者和前者)的情况。这是一种 <strong>交叉编译</strong> (Cross Compile)。</p>
<p>当然,这只是使得我们之后在 <code class="docutils literal notranslate"><span class="pre">cargo</span> <span class="pre">build</span></code> 的时候不必再加上 <code class="docutils literal notranslate"><span class="pre">--target</span></code> 参数的一个小 trick。如果我们现在 <code class="docutils literal notranslate"><span class="pre">cargo</span> <span class="pre">build</span></code> ,还是会和
上一小节一样出现找不到标准库 std 的错误。于是我们开始着手移除标准库。当然,这会产生一些副作用。</p>
<div class="section" id="println">
Y
Yifan Wu 已提交
190
<h2>移除 println! 宏<a class="headerlink" href="#println" title="永久链接至标题"></a></h2>
Y
Yifan Wu 已提交
191 192
<p>我们在 <code class="docutils literal notranslate"><span class="pre">main.rs</span></code> 的开头加上一行 <code class="docutils literal notranslate"><span class="pre">#![no_std]</span></code> 来告诉 Rust 编译器不使用 Rust 标准库 std 转而使用核心库 core。编译器报出如下错误:</p>
<div class="admonition error">
Y
Yifan Wu 已提交
193
<p class="admonition-title">错误</p>
Y
Yifan Wu 已提交
194 195 196 197 198 199 200 201 202 203 204 205 206 207
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> cargo build
<span class="go">   Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)</span>
<span class="go">error: cannot find macro `println` in this scope</span>
<span class="go">--&gt; src/main.rs:4:5</span>
<span class="go">  |</span>
<span class="go">4 |     println!(&quot;Hello, world!&quot;);</span>
<span class="go">  |     ^^^^^^^</span>
</pre></div>
</div>
</div>
<p>我们之前提到过, println! 宏是由标准库 std 提供的,且会使用到一个名为 write 的系统调用。现在我们的条件还不足以自己实现一个 println! 宏,由于
使用了系统调用也不能在核心库 core 中找到它。我们目前先通过将它注释掉来绕过它。</p>
</div>
<div class="section" id="panic-handler">
Y
Yifan Wu 已提交
208
<h2>提供语义项 panic_handler<a class="headerlink" href="#panic-handler" title="永久链接至标题"></a></h2>
Y
Yifan Wu 已提交
209
<div class="admonition error">
Y
Yifan Wu 已提交
210
<p class="admonition-title">错误</p>
Y
Yifan Wu 已提交
211 212 213 214 215 216 217 218 219 220 221 222
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> cargo build
<span class="go">   Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)</span>
<span class="go">error: `#[panic_handler]` function required, but not found</span>
</pre></div>
</div>
</div>
<p>在使用 Rust 编写应用程序的时候,我们常常在遇到了一些无法恢复的致命错误导致程序无法继续向下运行的时候手动或自动调用 panic! 宏来并打印出错的
位置让我们能够意识到它的存在,并进行一些后续处理。panic! 宏最典型的应用场景包括断言宏 assert! 失败或者对 <code class="docutils literal notranslate"><span class="pre">Option::None/Result::Err</span></code>
进行 <code class="docutils literal notranslate"><span class="pre">unwrap</span></code> 操作。</p>
<p>在标准库 std 中提供了 panic 的处理函数 <code class="docutils literal notranslate"><span class="pre">#[panic_handler]</span></code>,其大致功能是打印出错位置和原因并杀死当前应用。可惜的是在核心库 core 中并没有提供,
因此我们需要自己实现 panic 处理函数。</p>
<div class="admonition note">
Y
Yifan Wu 已提交
223
<p class="admonition-title">注解</p>
Y
Yifan Wu 已提交
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
<p><strong>Rust 语义项 lang_items</strong></p>
<p>Rust 编译器内部的某些功能的实现并不是硬编码在语言内部的,而是以一种可插入的形式在库中提供。库只需要通过某种方式告诉编译器它的某个方法实现了
编译器内部的哪些功能,编译器就会采用库提供的方法来实现它内部对应的功能。通常只需要在库的方法前面加上一个标记即可。</p>
</div>
<p>我们开一个新的子模块 <code class="docutils literal notranslate"><span class="pre">lang_items.rs</span></code> 保存这些语义项,在里面提供 panic 处理函数的实现并通过标记通知编译器采用我们的实现:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/lang_items.rs</span>
<span class="k">use</span><span class="w"> </span><span class="n">core</span>::<span class="n">panic</span>::<span class="n">PanicInfo</span><span class="p">;</span><span class="w"></span>

<span class="cp">#[panic_handler]</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">panic</span><span class="p">(</span><span class="n">_info</span>: <span class="kp">&amp;</span><span class="nc">PanicInfo</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">loop</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>注意,panic 处理函数的函数签名需要一个 <code class="docutils literal notranslate"><span class="pre">PanicInfo</span></code> 的不可变借用作为输入参数,它在核心库中得以保留,这也是我们第一次与核心库打交道。之后我们
会从 <code class="docutils literal notranslate"><span class="pre">PanicInfo</span></code> 解析出错位置并打印出来,然后杀死应用程序。但目前我们什么都不做只是在原地 loop。</p>
</div>
<div class="section" id="main">
Y
Yifan Wu 已提交
242
<h2>移除 main 函数<a class="headerlink" href="#main" title="永久链接至标题"></a></h2>
Y
Yifan Wu 已提交
243
<div class="admonition error">
Y
Yifan Wu 已提交
244
<p class="admonition-title">错误</p>
Y
Yifan Wu 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ cargo build
   Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)
error: requires `start` lang_item
</pre></div>
</div>
</div>
<p>编译器提醒我们缺少一个名为 <code class="docutils literal notranslate"><span class="pre">start</span></code> 的语义项。我们回忆一下,之前提到语言标准库和三方库作为应用程序的执行环境,需要负责在执行应用程序之前进行
一些初始化工作,然后才跳转到应用程序的入口点(也就是跳转到我们编写的 <code class="docutils literal notranslate"><span class="pre">main</span></code> 函数)开始执行。事实上 <code class="docutils literal notranslate"><span class="pre">start</span></code> 语义项正代表着标准库 std 在
执行应用程序之前需要进行的一些初始化工作。由于我们禁用了标准库,编译器也就找不到这项功能的实现了。</p>
<p>最简单的解决方案就是压根不让编译器使用这项功能。我们在 <code class="docutils literal notranslate"><span class="pre">main.rs</span></code> 的开头加入设置 <code class="docutils literal notranslate"><span class="pre">#![no_main]</span></code> 告诉编译器我们没有一般意义上的 <code class="docutils literal notranslate"><span class="pre">main</span></code> 函数,
并将原来的 <code class="docutils literal notranslate"><span class="pre">main</span></code> 函数删除。在失去了 <code class="docutils literal notranslate"><span class="pre">main</span></code> 函数的情况下,编译器也就不需要完成所谓的初始化工作了。</p>
<p>至此,我们成功移除了标准库的依赖并完成裸机平台上的构建。</p>
<div class="highlight-console notranslate"><div class="highlight"><pre><span></span><span class="gp">$</span> cargo build
<span class="go">   Compiling os v0.1.0 (/home/shinbokuow/workspace/v3/rCore-Tutorial-v3/os)</span>
<span class="go">    Finished dev [unoptimized + debuginfo] target(s) in 0.06s</span>
</pre></div>
</div>
<p>目前的代码如下:</p>
<div class="highlight-rust notranslate"><div class="highlight"><pre><span></span><span class="c1">// os/src/main.rs</span>
<span class="cp">#![no_std]</span><span class="w"></span>
<span class="cp">#![no_main]</span><span class="w"></span>

<span class="k">mod</span> <span class="nn">lang_items</span><span class="p">;</span><span class="w"></span>

<span class="c1">// os/src/lang_items.rs</span>
<span class="k">use</span><span class="w"> </span><span class="n">core</span>::<span class="n">panic</span>::<span class="n">PanicInfo</span><span class="p">;</span><span class="w"></span>

<span class="cp">#[panic_handler]</span><span class="w"></span>
<span class="k">fn</span> <span class="nf">panic</span><span class="p">(</span><span class="n">_info</span>: <span class="kp">&amp;</span><span class="nc">PanicInfo</span><span class="p">)</span><span class="w"> </span>-&gt; <span class="o">!</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="k">loop</span><span class="w"> </span><span class="p">{}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>本小节我们固然脱离了标准库,通过了编译器的检验,但也是伤筋动骨,将原有的很多功能弱化甚至直接删除,看起来距离在 RV64GC 平台上打印
<code class="docutils literal notranslate"><span class="pre">Hello</span> <span class="pre">world!</span></code> 相去甚远了(我们甚至连 println! 和 <code class="docutils literal notranslate"><span class="pre">main</span></code> 函数都删除了)。不要着急,接下来我们会以自己的方式来重塑这些
功能,并最终完成我们的目标。</p>
Y
Yifan Wu 已提交
281 282 283 284 285 286
<div class="admonition note">
<p class="admonition-title">注解</p>
<p><strong>在 x86_64 平台上移除标准库依赖</strong></p>
<p>有兴趣的同学可以将目标平台换回之前默认的 <code class="docutils literal notranslate"><span class="pre">x86_64-unknown-linux-gnu</span></code> 并重复本小节所做的事情,比较两个平台从 ISA 到操作系统
的差异。可以参考 <a class="reference external" href="https://os.phil-opp.com/freestanding-rust-binary/">BlogOS 的相关内容</a></p>
</div>
Y
Yifan Wu 已提交
287 288 289 290 291 292 293 294 295 296 297
</div>
</div>


           </div>
           
          </div>
          <footer>
  
    <div class="rst-footer-buttons" role="navigation" aria-label="footer navigation">
      
Y
Yifan Wu 已提交
298
        <a href="3minimal-rt.html" class="btn btn-neutral float-right" title="重建最小化运行时" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right"></span></a>
Y
Yifan Wu 已提交
299 300 301 302 303 304 305 306 307 308 309
      
      
        <a href="1app-ee-platform.html" class="btn btn-neutral float-left" title="应用程序运行环境与平台支持" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left"></span> Previous</a>
      
    </div>
  

  <hr/>

  <div role="contentinfo">
    <p>
Y
Yifan Wu 已提交
310
        &copy; Copyright 2020, Yifan Wu
Y
Yifan Wu 已提交
311 312 313

    </p>
  </div>
Y
Yifan Wu 已提交
314
  Built with <a href="http://sphinx-doc.org/">Sphinx</a> using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>. 
Y
Yifan Wu 已提交
315 316 317 318 319 320 321 322 323 324 325

</footer>

        </div>
      </div>

    </section>

  </div>
  

Y
Yifan Wu 已提交
326

Y
Yifan Wu 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339
  <script type="text/javascript">
      jQuery(function () {
          SphinxRtdTheme.Navigation.enable(true);
      });
  </script>

  
  
    
   

</body>
</html>