<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: tyfkda</title>
    <description>The latest articles on DEV Community by tyfkda (@tyfkda).</description>
    <link>https://dev.to/tyfkda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F70562%2F206fe9f8-e91f-4499-a417-16788b2be43f.png</url>
      <title>DEV Community: tyfkda</title>
      <link>https://dev.to/tyfkda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tyfkda"/>
    <language>en</language>
    <item>
      <title>Running a C compiler in a browser</title>
      <dc:creator>tyfkda</dc:creator>
      <pubDate>Fri, 05 Feb 2021 09:05:59 +0000</pubDate>
      <link>https://dev.to/tyfkda/running-a-c-compiler-in-a-browser-4g9h</link>
      <guid>https://dev.to/tyfkda/running-a-c-compiler-in-a-browser-4g9h</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/tyfkda/xcc/"&gt;My own C compiler&lt;/a&gt; is designed for x86-64 and outputs ELF64 binary. My plan was that if I could output code that could run on x86-64, I could run it on my home computer, and I would be able to do this for the next 10 years. However, with the emergence of various processors, it seems that x86 may not remain the mainstream.&lt;/p&gt;

&lt;p&gt;I also experienced the ability &lt;a href="https://github.com/tyfkda/galangua"&gt;to compile code written in Rust to WASM&lt;/a&gt; and &lt;a href="https://tyfkda.github.io/galangua/"&gt;run it in a browser&lt;/a&gt;. I was quite surprised to find out that I can run code written in a language that can do low-level things like memory manipulation with pointers in a browser. I was quite surprised.&lt;/p&gt;

&lt;p&gt;So I thought I'd try to make it possible to output wasm from the C compiler.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tyfkda.github.io/xcc/"&gt;Online Demo&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture of WASM
&lt;/h3&gt;

&lt;p&gt;I looked up the architecture of WASM a while ago, and the features are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stack machine instruction set (no registers)&lt;/li&gt;
&lt;li&gt;Local variables can be used&lt;/li&gt;
&lt;li&gt;Only &lt;code&gt;i32&lt;/code&gt;, &lt;code&gt;i64&lt;/code&gt;, &lt;code&gt;f32&lt;/code&gt;, &lt;code&gt;f64&lt;/code&gt; types are supported (not even strings)&lt;/li&gt;
&lt;li&gt;Jumps can only be control-syntactic jumps (out of a block or back in a loop), not to a label (address)&lt;/li&gt;
&lt;li&gt;There is no GC.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As for the data types that can be handled, there are no useful ones such as objects or strings, only byte array that can be manipulated, but I think this is a sufficient level to bring from a language specification of the level of C.&lt;/p&gt;

&lt;h3&gt;
  
  
  Policy for outputting WASM binaries from a C compiler
&lt;/h3&gt;

&lt;p&gt;The original compiler was designed to convert to a register machine instruction set:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Front end (parser): C source -&amp;gt; Abstract Syntax Tree (AST)&lt;/li&gt;
&lt;li&gt;Middle end (intermediate representation): AST -&amp;gt; Intermediate Representation (IR)&lt;/li&gt;
&lt;li&gt;Backend: IR -&amp;gt; x86-64 binary (ELF64 format)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It would be nice to be able to switch the output target by sharing the middle end and replacing the backend, but it's a bit difficult.&lt;/p&gt;

&lt;p&gt;In the middle end, jumps are converted to basic blocks, and finally to label jumps. However, in WASM, the jump is a control structure, and you can't place a label at an arbitrary point and make it jump. So if we want to do this, we need to recover the control structure from the label jump. It may be possible to recover the control structure by analyzing the control flow graph, but I don't think it's easy.&lt;/p&gt;

&lt;p&gt;There are some other points that seem troublesome.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The calculation of the expression has been converted to an operation in three-address code between virtual registers, and it needs to be converted back to the stack machine method.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the AST stage can be used as-is, I decided to share only the front-end and output the wasm binary directly from the AST.&lt;/p&gt;

&lt;h3&gt;
  
  
  A few implementation points
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Handling of local variables other than numeric types
&lt;/h4&gt;

&lt;p&gt;WASM can only handle 32/64 bit integer/floating-point number types as local variables, not structures or arrays. What to do is to store them in linear memory.&lt;/p&gt;

&lt;p&gt;It is necessary to manage which part of the linear memory to use by yourself. Therefore, we need to prepare a global variable that represents the stack pointer, store it in a local variable that represents the base pointer at the beginning of a function, modify the stack pointer, and then restore it when we exit.&lt;/p&gt;

&lt;p&gt;If a reference is taken by &lt;code&gt;&amp;amp;&lt;/code&gt; even if it is a numeric type, it is necessary to be able to rewrite it via the pointer, so it cannot be a local variable and should be placed in linear memory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Returning from the middle of a function
&lt;/h4&gt;

&lt;p&gt;When exiting with a value by &lt;code&gt;return&lt;/code&gt; from the middle of a function, a real processor such as x86 will return to the caller with a value in the &lt;code&gt;rax&lt;/code&gt; register according to ABI. In WASM, it is also possible to exit from a function and return the top of the stack with the &lt;code&gt;return&lt;/code&gt; instruction, but there are cases where it is necessary to restore the stack pointer as described in the previous paragraph, so I want to unify the process of exiting from a function (epilogue).&lt;/p&gt;

&lt;p&gt;In this case, we cannot use &lt;code&gt;return&lt;/code&gt; from the middle of the function, so we need to prepare a local variable to store the return value, store it in the variable, jump to the epilogue, process the epilogue, retrieve the return value, and return it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Handling of assignment expressions
&lt;/h4&gt;

&lt;p&gt;In C language, assignment is an expression, so it can be connected to multiple expressions or mixed with other expressions. However, in WASM, storing a value in a local variable (&lt;code&gt;local.set&lt;/code&gt;) or in linear memory (&lt;code&gt;i32.store&lt;/code&gt;) removes the value from the top of the stack. Since there is no instruction like &lt;code&gt;dup&lt;/code&gt; to duplicate the value on the stack, it is not possible to keep the assigned value (although it is possible to keep the value of a local variable while storing it with the &lt;code&gt;local.tee&lt;/code&gt; instruction).&lt;/p&gt;

&lt;p&gt;Therefore, the assignment expression is treated as &lt;code&gt;void&lt;/code&gt;, and the value cannot keep alive. If the value of the assignment expression is still to be used, a local variable is allocated internally and converted to a comma expression (&lt;code&gt;l = r&lt;/code&gt; is converted to &lt;code&gt;((void)(tmp = r), (void)(l = tmp), tmp))&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Switch statement
&lt;/h4&gt;

&lt;p&gt;In WASM, only structured jumps are possible, but how to implement a &lt;code&gt;switch&lt;/code&gt; statement? I was wondering how to implement the &lt;code&gt;switch&lt;/code&gt; statement, but it was nothing, I just had to nest as many &lt;code&gt;block&lt;/code&gt;s as the number of &lt;code&gt;case&lt;/code&gt;s and &lt;code&gt;br&lt;/code&gt; each one.&lt;/p&gt;

&lt;p&gt;There is also an instruction called &lt;code&gt;br_table&lt;/code&gt;, which allows you to do table jumps instead of &lt;code&gt;br_if&lt;/code&gt; in order (I haven't tried it).&lt;/p&gt;

&lt;h4&gt;
  
  
  Variable Length Arguments
&lt;/h4&gt;

&lt;p&gt;The number of arguments of a function and their types must be fixed in WASM. As for how to handle variable-length arguments, we'll pass them in linear memory. We can internally pass function arguments to &lt;code&gt;...&lt;/code&gt; Internally, convert the function argument to the argument before &lt;code&gt;...&lt;/code&gt; + pointer to store the variable length arguments.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pointer length
&lt;/h4&gt;

&lt;p&gt;The pointer is treated as an offset in the linear memory, but since the offset is &lt;code&gt;u32&lt;/code&gt;, the pointer should be 32 bits long. Therefore, I decided to use &lt;code&gt;sizeof(void*) == sizeof(long) == sizeof(int) == 4&lt;/code&gt;. The data type model is called &lt;code&gt;ILP32&lt;/code&gt;. &lt;code&gt;i64&lt;/code&gt; will be handled as a &lt;code&gt;long long&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It is recommended to have the &lt;code&gt;__ILP32__&lt;/code&gt; macro pre-defined so that the code can determine this.&lt;/p&gt;

&lt;h4&gt;
  
  
  Function call using function pointer
&lt;/h4&gt;

&lt;p&gt;In WASM, normal function call is not by name or label, but by an index that is assigned to the function in order. In order to handle function pointer, it was not possible to do so by using the index.&lt;/p&gt;

&lt;p&gt;You need to register the function you want to handle as a function pointer in a &lt;code&gt;table&lt;/code&gt;, and use that index.&lt;/p&gt;

&lt;h4&gt;
  
  
  Old Function Prototype Declarations
&lt;/h4&gt;

&lt;p&gt;In the prototype declarations of functions in the old C language, parameters can be omitted. In that case, the function is compiled assuming that the type of the argument given by the caller matches the entity, and if it does not, it will malfunction.&lt;/p&gt;

&lt;p&gt;In WASM, if the type or number of arguments of the function to be called is not correct, a runtime error will occur, so make it an error at compile time.&lt;/p&gt;

&lt;h4&gt;
  
  
  Runtime Environment
&lt;/h4&gt;

&lt;p&gt;One of the advantages of compiling to binary is that you don't have to write a runtime because everything is resolved at compile time. However, this does not mean that the standalone executable is truly independent, but rather depends on the OS system calls.&lt;/p&gt;

&lt;p&gt;In the same way, the world of wasm binaries only allows computations, so if you want to communicate with the outside world, you need to prepare a call equivalent to a system call. From wasm, it can be executed as a call to an &lt;code&gt;import&lt;/code&gt;ed function. Prepare functions such as &lt;code&gt;open&lt;/code&gt; and &lt;code&gt;read&lt;/code&gt; that are equivalent to &lt;code&gt;unistd&lt;/code&gt; and make them available.&lt;/p&gt;

&lt;h3&gt;
  
  
  Running in a browser
&lt;/h3&gt;

&lt;p&gt;As usual, if you compile the source of the compiler itself, you can get a compiler that runs as WebAssembly, which is self-hosting. It's interesting to note that cross-compilation is included this time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;C compiler source (wcc.c) → gcc on Mac → C compiler running on Mac that can emit wasm (wcc on Mac)&lt;/li&gt;
&lt;li&gt;C compiler source (wcc.c) → wcc on Mac → C compiler running on wasm that can emit wasm (wcc on wasm)&lt;/li&gt;
&lt;li&gt;Prepare a runtime and run wcc on wasm in a browser.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Just by enabling the C compiler to emit wasm, you've got a C compiler that automatically runs on your browser! This is a good deal.&lt;/p&gt;

&lt;p&gt;After that, I'll make up a file system, and incorporate Ace editor as a text editor that runs in the browser, so that I can compile and execute with a button.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problems
&lt;/h3&gt;

&lt;p&gt;Some of the problems with WASM, not necessarily on the browser, are&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asynchronous processing is not possible.&lt;/li&gt;
&lt;li&gt;You can't wait until something is done synchronously, because you can't explicitly give away the process.&lt;/li&gt;
&lt;li&gt;Cannot &lt;code&gt;fork&lt;/code&gt; a process&lt;/li&gt;
&lt;li&gt;Cannot do global escaping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In JavaScript, asynchronous processing is possible with &lt;code&gt;Promise&lt;/code&gt;, but it is currently not possible with wasm. If I had to do it, I'd separate functions in the middle and let them sleep the process once... but that's not possible in places where function calls are nested.&lt;/p&gt;

&lt;p&gt;If you can't do global escaping, you can't handle exceptions, which is fine in C and Rust, but how do you handle exceptions in C++?&lt;/p&gt;

&lt;h3&gt;
  
  
  Unimplemented features
&lt;/h3&gt;

&lt;p&gt;Jumps with &lt;code&gt;goto&lt;/code&gt; are not supported because they cannot be easily converted to structural jumps. Disabling &lt;code&gt;goto&lt;/code&gt; is not enough, but looping over a &lt;code&gt;case&lt;/code&gt; inside a &lt;code&gt;switch&lt;/code&gt; breaks the structure (&lt;a href="https://en.wikipedia.org/wiki/Duff%27s_device"&gt;Duff's device&lt;/a&gt;), so it is not supported.&lt;/p&gt;

&lt;p&gt;Others: passing/returning values of structs, compound literals.&lt;/p&gt;

&lt;h3&gt;
  
  
  Impressions
&lt;/h3&gt;

&lt;p&gt;I thought it would be interesting to be able to run code written in C on a browser, but then I realized that there is no need for me to go through the trouble of coding in C on a browser... orz&lt;/p&gt;

&lt;p&gt;jp: &lt;a href="https://tyfkda.github.io/blog/2021/02/04/c-on-browser.html"&gt;https://tyfkda.github.io/blog/2021/02/04/c-on-browser.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>c</category>
      <category>compiler</category>
      <category>webassembly</category>
    </item>
    <item>
      <title>Implement `pwd` command on xv6</title>
      <dc:creator>tyfkda</dc:creator>
      <pubDate>Thu, 07 Jun 2018 14:19:26 +0000</pubDate>
      <link>https://dev.to/tyfkda/implement-pwd-command-on-xv6-gh5</link>
      <guid>https://dev.to/tyfkda/implement-pwd-command-on-xv6-gh5</guid>
      <description>&lt;p&gt;I just started playing with &lt;a href="https://github.com/mit-pdos/xv6-public"&gt;xv6&lt;/a&gt;, re-implementation of Unix version 6. It can easily build and run.&lt;/p&gt;

&lt;p&gt;I thought implementing some command is a good practice, so I decided to add simple one, &lt;code&gt;pwd&lt;/code&gt;. It can be made in pure user land, and no additional system call required.&lt;/p&gt;

&lt;h3&gt;
  
  
  Extract file information on xv6
&lt;/h3&gt;

&lt;p&gt;Referring to &lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/ls.c"&gt;ls.c&lt;/a&gt;, you can extract file information (&lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/stat.h#L5"&gt;struct &lt;code&gt;stat&lt;/code&gt;&lt;/a&gt;) using &lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/ulib.c#L71"&gt;&lt;code&gt;stat&lt;/code&gt;&lt;/a&gt; function.&lt;/p&gt;

&lt;p&gt;You can also enumerate directory entries calling &lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/user.h#L14"&gt;&lt;code&gt;open&lt;/code&gt;&lt;/a&gt; function with directory path, &lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/user.h#L10"&gt;&lt;code&gt;read&lt;/code&gt;&lt;/a&gt; contents as &lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/fs.h#L53"&gt;struct &lt;code&gt;dirent&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Find absolute path
&lt;/h3&gt;

&lt;p&gt;I am not familiar with concept of Unix, so looking for the code, and it seems &lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/file.h#L13"&gt;struct &lt;code&gt;inode&lt;/code&gt;&lt;/a&gt; (and its &lt;code&gt;inum&lt;/code&gt;, inode number) is the key part for the file system. But interestingly, it doesn't have its file name. To get file name, you have to enumerate its directory and search for &lt;code&gt;inum&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To get absolute path, you have to get file name recursively, until reach to the root.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code
&lt;/h3&gt;

&lt;p&gt;Here is the &lt;code&gt;main&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include "types.h"
#include "fcntl.h"
#include "fs.h"
#include "stat.h"
#include "user.h"
&lt;/span&gt;
&lt;span class="cp"&gt;#define NULL   ((void*)0)
#define FALSE  (0)
#define TRUE   (1)
&lt;/span&gt;
&lt;span class="cp"&gt;#define PATH_SEPARATOR   "/"
&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;goUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;dirlookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"pwd failed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;getcwd&lt;/code&gt; function returns current working directory to the given buffer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;getcwd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="n"&gt;strcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;goUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;strcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PATH_SEPARATOR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ancestorPath&lt;/code&gt; holds relative path to ancestors. It becomes &lt;code&gt;"."&lt;/code&gt;, &lt;code&gt;"./.."&lt;/code&gt;, &lt;code&gt;"./../.."&lt;/code&gt;, ... and is used to pass to &lt;code&gt;stat&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;goUp&lt;/code&gt; function goes to parent directory for &lt;code&gt;ancestorPath&lt;/code&gt;, and find the absolute path, recursively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;goUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;strcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ancestorPath&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;PATH_SEPARATOR&lt;/span&gt; &lt;span class="s"&gt;".."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;stat&lt;/span&gt; &lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ino&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// No parent directory exists: must be the root.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;foundPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;O_RDONLY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;goUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;st&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ancestorPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resultPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;strcpy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PATH_SEPARATOR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PATH_SEPARATOR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// Find current directory.&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirlookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="n"&gt;foundPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;foundPath&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if you are at the root directory, you can get &lt;code&gt;stat&lt;/code&gt; for the parent direcotry without error (and you can &lt;code&gt;cd ..&lt;/code&gt;). It seems you have to detect you are at the root if parent's and current directory's &lt;code&gt;ino&lt;/code&gt; are same.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dirlookup&lt;/code&gt; function finds file name for the given inode number from its parent directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="c1"&gt;// @param fd   file descriptor for a directory.&lt;/span&gt;
&lt;span class="c1"&gt;// @param ino  target inode number.&lt;/span&gt;
&lt;span class="c1"&gt;// @param p    [out] file name (part of absPath), overwritten by the file name of the ino.&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;dirlookup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;dirent&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inum&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inum&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;ino&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;memmove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DIRSIZ&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;DIRSIZ&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;TRUE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;FALSE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build and add to file image
&lt;/h3&gt;

&lt;p&gt;You can easily add your extra command to image file on xv6 . Modify &lt;a href="https://github.com/mit-pdos/xv6-public/blob/master/Makefile#L161"&gt;UPROGS in Makefile&lt;/a&gt; with naming convention, add &lt;code&gt;_pwd&lt;/code&gt; to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
/
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;foo
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;foo/bar
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;foo/bar
&lt;span class="nv"&gt;$ &lt;/span&gt;/pwd
/foo/bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I stumbled using &lt;code&gt;pwd&lt;/code&gt; at &lt;code&gt;/foo/bar&lt;/code&gt;. It seems xv6 doesn't have environment variables, and search path in a shell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;  &lt;span class="c"&gt;# &amp;lt;= without '/' causes exec error, because cannot find the command.&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt;: fail
&lt;span class="nb"&gt;exec pwd &lt;/span&gt;failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have to add &lt;code&gt;/&lt;/code&gt; to point exact command path on xv6.&lt;/p&gt;

</description>
      <category>xv6</category>
      <category>c</category>
    </item>
  </channel>
</rss>
