<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
	<title>Okx&#39;s blog</title>
	<link>http://okx.sh/</link>
	<description>Recent content on Okx&#39;s blog</description>
	<generator>Hugo -- gohugo.io</generator>
	<language>en-gb</language>
    
        <atom:link href="http://okx.sh/index.xml" rel="self" type="application/rss+xml" />
	
	
	<item>
		<title>Introduction to x86 assembly on Linux</title>
		<link>http://okx.sh/assembly/</link>
		<pubDate>Wed, 20 Jul 2022 13:14:36 +0100</pubDate>
		
		<guid>http://okx.sh/assembly/</guid>
		<description>&lt;p&gt;Knowledge of assembly is an important tool for any programmer. It allows you to interact directly with the CPU, and is an often overlooked but crucial part of any computer. This is a tutorial on assembly as well as low-level programming in general, to help give one a more complete understanding of the system that they might use daily.&lt;/p&gt;
&lt;p&gt;Here is a Hello World program in the NASM (Netwise Assembler) dialect of assembly, for Linux on x86-64:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nasm&#34; data-lang=&#34;nasm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;section&lt;/span&gt; .rodata &lt;span style=&#34;color:#75715e&#34;&gt;; (1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  hello_world_string: &lt;span style=&#34;color:#66d9ef&#34;&gt;db&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;10&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;; (2)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  hello_world_string_len: &lt;span style=&#34;color:#75715e&#34;&gt;; (3)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;section&lt;/span&gt; .text &lt;span style=&#34;color:#75715e&#34;&gt;; (4)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;global&lt;/span&gt; _start &lt;span style=&#34;color:#75715e&#34;&gt;; (5)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;_start:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mov&lt;/span&gt; rax, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;; (6)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mov&lt;/span&gt; rdi, &lt;span style=&#34;color:#ae81ff&#34;&gt;1&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;; (7)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mov&lt;/span&gt; rsi, hello_world_string &lt;span style=&#34;color:#75715e&#34;&gt;; (8)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;lea&lt;/span&gt; rdx, [hello_world_string_len &lt;span style=&#34;color:#f92672&#34;&gt;-&lt;/span&gt; hello_world_string] &lt;span style=&#34;color:#75715e&#34;&gt;; (9)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;; (10)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mov&lt;/span&gt; rax, &lt;span style=&#34;color:#ae81ff&#34;&gt;60&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;; (11)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;mov&lt;/span&gt; rdi, &lt;span style=&#34;color:#ae81ff&#34;&gt;0&lt;/span&gt; &lt;span style=&#34;color:#75715e&#34;&gt;; (12)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;syscall&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To build and run this program, place it into a file named &lt;code&gt;hello_world.s&lt;/code&gt;, then run &lt;code&gt;nasm -f elf64 hello_world.s&lt;/code&gt; and &lt;code&gt;ld hello_world.o -o hello_world&lt;/code&gt;. Now you can run the binary &lt;code&gt;./hello_world&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;At (1), we define a section named &lt;code&gt;rodata&lt;/code&gt; which will be placed in our binary. This is a section for containing &lt;em&gt;read-only data&lt;/em&gt;. Other data sections include &lt;code&gt;data&lt;/code&gt; which is &lt;em&gt;read and write data&lt;/em&gt; and &lt;code&gt;bss&lt;/code&gt; which is &lt;em&gt;uninitialized data&lt;/em&gt;. They will be covered later.&lt;/p&gt;
&lt;p&gt;At (2), the bytes (&lt;strong&gt;db&lt;/strong&gt; means &lt;strong&gt;d&lt;/strong&gt;efine &lt;strong&gt;b&lt;/strong&gt;ytes) representing the ANSI for &amp;ldquo;Hello, World!&amp;rdquo;, followed by the byte 10, which is a newline, will be inserted directly into the binary. &lt;code&gt;hello_world_string&lt;/code&gt; is a NASM &lt;strong&gt;label&lt;/strong&gt; which refers to start of the string (&amp;ldquo;H&amp;rdquo;). At (3), &lt;code&gt;hello_world_string_len&lt;/code&gt; is a label which represents the byte immediately after the new line, and is used to compute the length of the string.&lt;/p&gt;
&lt;p&gt;(4) defines the &lt;code&gt;text&lt;/code&gt; section which is where our instructions are actually placed. Then, at (5), to ensure that Linux knows where to start executing our program, we define the special label &lt;code&gt;_start&lt;/code&gt; and make it global so that Linux can &amp;ldquo;see&amp;rdquo; it.&lt;/p&gt;
&lt;p&gt;The next section is a little bit more complicated. The way in which programs can interact with the Linux kernel - necessary to do anything interesting! - is done via &lt;strong&gt;system calls&lt;/strong&gt;, also called a &lt;strong&gt;syscall&lt;/strong&gt;. There are &lt;a href=&#34;https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl&#34;&gt;hundreds of syscalls on Linux&lt;/a&gt; which allow you to do anything from allocate memory, to establish network connections, do file I/O, and more. The Linux kernel is unusual because its syscall interface is very stable compared to Windows or FreeBSD/OpenBSD, so it is possible to program against it directly. However, most programs use a library to abstract this away; often libc, also known as the C standard library. The main benefit of this is that you can easy compile for different operating systems, as the syscall interface is different for each one.&lt;/p&gt;
&lt;p&gt;The x86-64 architecture is an updated version of the x86-32 architecture, which had the limitation of a maximum of 4 GiB of memory. x86 can refer to either or both architectures, although x64 is sometimes used to mean x86-64. The x86-64 architecture has 16 general-purpose &lt;strong&gt;registers&lt;/strong&gt; (there are more registers, but they have specific uses), which are 8 bytes or 64 bits each. They are like RAM, but orders of magnitudes faster to read and write from. They are also necessary to speak to the Linux kernel, as it expects its syscall data to be in specific registers. Linux uses the &lt;code&gt;rax&lt;/code&gt; register for the syscall name. The first character, &lt;code&gt;r&lt;/code&gt;, means that it is 64 bits long, and &lt;code&gt;ax&lt;/code&gt; means that it is the &lt;strong&gt;a&lt;/strong&gt;cumulator register, although this meaning has long become obsolete and it is now a general purpose register.&lt;/p&gt;
&lt;p&gt;The assembly instruction &lt;code&gt;mov&lt;/code&gt; &lt;em&gt;moves&lt;/em&gt; the second argument (such as 1) into the first argument (such as the register rax). It is the most basic instruction in assembly.&lt;/p&gt;
&lt;p&gt;Looking at (6), according to the &lt;a href=&#34;https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_64.tbl&#34;&gt;table&lt;/a&gt; linked earlier, 1 refers to the &amp;ldquo;write&amp;rdquo; syscall. This allows you to write data to a &lt;strong&gt;file descriptor&lt;/strong&gt;, which may be standard output, standard input, standard error, or an actual file. This is a common pattern in Linux, where files have the same interface as other forms of I/O. (7) provides the actual file descriptor, which is a constant 1 to mean standard output. If you are programming in assembly often, you may create shortcuts for this, to reduce mental load. It may be surprising to use numbers, and have to manually give everything a meaninful name, but this is the most efficient form of communication, and helps you understand what is really happening.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;An example of using macros to make assembly code easier to read:&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-nasm&#34; data-lang=&#34;nasm&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mox&lt;/span&gt; rax, SYS_WRITE
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;mov&lt;/span&gt; rdi, STDOUT
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Linux, syscall arguments are expected in specific registers. We have seen that &lt;code&gt;rax&lt;/code&gt; is used for the syscall itself and &lt;code&gt;rdi&lt;/code&gt; is used for the first argument. Subsequent arguments are represented by &lt;code&gt;rdi&lt;/code&gt;, &lt;code&gt;rsi&lt;/code&gt;, &lt;code&gt;rdx&lt;/code&gt;, &lt;code&gt;rcx&lt;/code&gt;, &lt;code&gt;r8&lt;/code&gt;, and &lt;code&gt;r9&lt;/code&gt;. The names of registers only get stranger the longer you look at them, but x86-64 has a lot of historical baggage so this is what you get I&amp;rsquo;m afraid. The kernel will also &amp;ldquo;clobber&amp;rdquo; - or change to an unknown value - the registers &lt;code&gt;rcx&lt;/code&gt; and &lt;code&gt;r11&lt;/code&gt; after a syscall so you cannot expect them to be the same.&lt;/p&gt;
&lt;p&gt;At (8), &lt;code&gt;rsi&lt;/code&gt; is loaded with a &lt;strong&gt;pointer&lt;/strong&gt; to the start of the &amp;ldquo;Hello, World!&amp;rdquo;, 10 string. If you are familiar with C, then pointers will be a simple concept, but if you are not, it is simply a &lt;em&gt;location in RAM&lt;/em&gt;. When our program is executed, RAM is loaded with all the instructions and data that we have provided in the assembly file. If you&amp;rsquo;re interested, loading instructions and data in the same place is known the &lt;em&gt;von Neumann&lt;/em&gt; model. It is useful to know about the alternatives, but we will keep it simple for now. So the &lt;code&gt;rsi&lt;/code&gt; register now tells us &lt;em&gt;where the first byte of the Hello World string is&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;However, this is not enough to actually print the string - we do not know where it ends. So, at (9) we calculate the length of the string using the &lt;code&gt;lea&lt;/code&gt; (load effective address) instruction, which is a handy shortcut to do maths which we won&amp;rsquo;t get into at the moment. The result is loaded into the next syscall argument register, &lt;code&gt;rdx&lt;/code&gt;, which is used by the &lt;code&gt;write&lt;/code&gt; syscall for the number of bytes after the pointer in rsi to actually write.&lt;/p&gt;
&lt;p&gt;At last, we make the &lt;code&gt;syscall&lt;/code&gt; instruction which jumps into the Linux kernel, printing &amp;ldquo;Hello, World!&amp;rdquo; and a newline to standard output (the console).&lt;/p&gt;
&lt;p&gt;Unfortunately, we are not done yet. We have not terminated the program. The CPU will keep trying to read instructions, and our program is placed at an arbitrary point in RAM. So, it will take whatever happens to be in RAM that is after our program, and treat it like an instruction. More often than not, this will result in the notorious &lt;code&gt;Segmentation Fault (core dumped)&lt;/code&gt; error, meaning we are trying to access a location in RAM that we&amp;rsquo;re not allowed to access.&lt;/p&gt;
&lt;p&gt;We need to tell the CPU to stop running the program, and this is done by another syscall, &lt;code&gt;exit&lt;/code&gt;, represented by the number 60 at (11). This requires one argument, which is 0 to indicate the program terminated successfully, so we pass that in the &lt;code&gt;rdi&lt;/code&gt; register (12). Finally, the program is terminated and it returns control to the user.&lt;/p&gt;
&lt;p&gt;In summary, we have written a &amp;ldquo;Hello, World&amp;rdquo; program in assembly language, and learned about various low-level programming concepts. Part 2 will go more in-depth on how you can actually Get Stuff Done in assembly.&lt;/p&gt;
</description>
	</item>
	
	</channel>
</rss>
