Say hello to x64 Assembly [part 3]


Some time ago i started to write a series of posts about assembly x64 programming. It is third part and it will be about stack. The stack is special region in memory (built into the CPU), which operates on the principle lifo (Last Input, First Output).

We have 16 general-purpose registers for temporary data storage. They are RAX, RBX, RCX, RDX, RDI, RSI, RBP, RSP and R8-R15. It's too few for serious applications. So we can store data in the stack. Yet another usage of stack is following: When we call a function, return address copied in stack. After end of function execution, address copied in commands counter (RIP) and application continue to executes from next place after function.

For example:

Here we can see that after application runnning, rax is equal to 1. Then we call a function incRax, which increases rax value to 1, and now rax value must be 2. After this execution continues from 8 line, where we compare rax value with 2. Also as we can read in System V AMD64 ABI, the first six function arguments passed in registers. They are:
  • rdi - first argument
  • rsi - second argument
  • rdx - third argument
  • rcx - fourth argument
  • r8 - fifth argument
  • r9 - sixth
Next arguments will be passed in stack. So if we have function like this:

Then first six arguments will be passed in registers, but 7 argument will be passed in stack.

Stack pointer

As i wroute about we have 16 general-purpose registers, and there are two interesting registers - RSP and RBP. RBP is the base pointer register. It points to the base of the current stack frame. RSP is the stack pointer, which points to the top of current stack frame.


We have two commands for work with stack:
  • push argument - increments stack pointer (RSP) and stores argument in location pointed by stack pointer
  • pop argument - copied data to argument from location pointed by stack pointer
Let's look on one simple example:

Here we can see that we put 1 to rax register and 2 to rdx register. After it we push to stack values of these registers. Stack works as LIFO (Last In First Out). So after this stack or our application will have following structure:
Then we copy value from stack which has address rsp + 8. It means we get address of top of stack, add 8 to it and copy data by this address to rax. After it rax value will be 1.


Let's see one example. We will write simple program, which will get two command line arguments. Will get sum of this arguments and print result.

First of all we define .data section with some values. Here we have four constants for linux syscalls, for sys_write, sys_exit and etc... And also we have two strings: First is just new line symbol and second is error message.

Let's look at .text section, which consists from code of program:

Let's try to understand, what is happening here: After _start label first instruction get first value from stack and puts it to rcx register. If we run application with command line arguments, all of their will be in stack after running in following order:
  • [rsp] - top of stack will contain arguments count.
  • [rsp + 8] - will contain argv[0]
  • [rsp + 16] - will contain argv[1]
  • and so on...
So we get command line arguments count and put it to rcx. After it we compare rcx with 3. And if they are not equal we jump to argcError label which just prints error message:

Why we compare with 3 when we have two arguments. It's simple. First argument is a program name, and all after it are command line arguments which we passed to program. Ok, if we passed two command line arguments we go next to 10 line. Here we shift rsp to 8 and thereby missing the first argument - the name of the program. Now rsp points to first command line argument which we passed. We get it with pop command and put it to rsi register and call function for converting it to integer. Next we read about str_to_int implementation. After our function ends to work we have integer value in rax register and we save it in r10 register. After this we do the same operation but with r11. In the end we have two integer values in r10 and r11 registers, now we can get sum of it with add command. Now we must convert result to string and print it. Let's see how to do it:

Here we put sum of command line arguments to rax register, set r12 to zero and jump to int_to_str. Ok now we have base of our program. We already know how to print string and we have what to print. Let's see at str_to_int and int_to_str implementation.

At the start of str_to_int, we set up rax to 0 and rcx to 10. Then we go to next label. As you can see in above example (first line before first call of str_to_int) we put argv[1] in rsi from stack. Now we compare first byte of rsi with 0, because every string ends with NULL symbol and if it is we return. If it is not 0 we copy it's value to one byte bl register and substract 48 from it. Why 48? All numbers from 0 to 9 have 48 to 57 codes in asci table. So if we substract from number symbol 48 (for example from 57) we get number. Then we multiply rax on rcx (which has value - 10). After this we increment rsi for getting next byte and loop again. Algorthm is simple. For example if rsi points to '5' '7' '6' '\000' sequence, then will be following steps:
  • rax = 0
  • get first byte - 5 and put it to rbx
  • rax * 10 --> rax = 0 * 10
  • rax = rax + rbx = 0 + 5
  • Get second byte - 7 and put it to rbx
  • rax * 10 --> rax = 5 * 10 = 50
  • rax = rax + rbx = 50 + 7 = 57
  • and loop it while rsi is not \000
After str_to_int we will have number in rax. Now let's look at int_to_str:

Here we put 0 to rdx and 10 to rbx. Than we exeute div rbx. If we look above at code before str_to_int call. We will see that rax contains integer number - sum of two command line arguments. With this instruction we devide rax value on rbx value and get reminder in rdx and whole part in rax. Next we add to rdx 48 and 0x0. After adding 48 we'll get asci symbol of this number and all strings much be ended with 0x0. After this we save symbol to stack, increment r12 (it's 0 at first iteration, we set it to 0 at the _start) and compare rax with 0, if it is 0 it means that we ended to convert integer to string. Algorithm step by step is following: For example we have number 23
  • 123 / 10. rax = 12; rdx = 3
  • rdx + 48 = "3"
  • push "3" to stack
  • compare rax with 0 if no go again
  • 12 / 10. rax = 1; rdx = 2
  • rdx + 48 = "2"
  • push "2" to stack
  • compare rax with 0, if yes we can finish function execution and we will have "2" "3" ... in stack
We implemented to useful function int_to_str and str_to_int for converting integer number to string and vice versa. Now we have sum of two integers which was converted into string and saved in the stack. We can print result:

We already know how to print string with sys_write syscall, but here is one interesting part. We must to calculate length of string. If you will look at int_to_str, you will see that we increment r12 register every iteration, so it contains amount of digits in our number. We must multiple it to 8 (because we pushed every symbol to stack) and it will be length of our string which need to print. After this we as everytime put 1 to rax (sys_write number), 1 to rdi (stdin), string length to rdx and pointer to the top of stack to rsi (start of string). And finish our program:

That's all.


It was third part of series of posts about x64 assembly programming in Linux. If you will have questions/suggestions write me a comment. Sour code of all examples you can find - here.

You can find all parts:

Say hello to x64 Assembly [part 2]

Say hello to x64 Assembly [part 2]

Some days ago I wrote the first blog post - introduction to x64 assembly - Say hello to x64 Assembly [part 1] which to my surprise caused great interest:
It motivates me even more to describe my way of learning. During this days I got many feedback from different people. There were many grateful words, but what is more important for me, there were many advices and adequate critics. Especially I want to say thank you words for great feedback to: And all who took a part in discussion at Reddit and Hacker News. There were many opinions, that first part was a not very clear for absolute beginner, that's why i decided to write more informative posts. So, let's start with second part of Say hello to x64 assembly.

Say hello to x64 Assembly [part 1]


There are many developers between us. We write a tons of code every day. Sometime, it is even not a bad code :) Every of us can easily write the simplest code like this:

Every of us can understand what's this C code does. But... How this code works at low level? I think that not all of us can answer on this question, and me too. I thought that i can write code on high level programming languages like Haskell, Erlang, Go and etc..., but i absolutely don't know how it works at low level, after compilation. So I decided to take a few deep steps down, to assembly, and to describe my learning way about this. Hope it will be interesting, not only for me. Something about 5 - 6 years ago I already used assembly for writing simple programs, it was in university and i used Turbo assembly and DOS operating system. Now I use Linux-x86-64 operating system. Yes, must be big difference between Linux 64 bit and DOS 16 bit. So let's start.

Short list of mercurial cheat sheets

I'm using git scm for work and pet project quite long time. If wikipedia doesn't lie, first release of git was in 2005. If i remember correctly, than I am using git since 2009. I knew about git at github :). Two weeks ago I watched classic presentation Linus Torvalds on git. There was a quote:
Hg (Mercurial) is pretty good, but git is better
It was not my first time that I heard Mercurial name. Yes, i head it many times in my life. But unfortunatelly i never used it. I was curious about this dvcs and i decided little plunge into it. Today i finished to read: Mercurial: The Definitive Guide by Bryan O'Sullivan:
It is a really great book, where Bryan describes work with mercural from the start (how to install it, hot to create mercurial repository etc...) to advanced themes (hg hooks, worksflows and etc...). I have no big expirience with mercurial but i had noticed two things for this time:
  • It is much easier than git
  • It is much slower than git
In other parts mercurial similar to git, same commands commit, init, tag and etc...

List of useful mercurial commands

Here is little list of mercurial cheat sheets for mercurial begginers as me: To clone remote mercurial repo to local Dir directory:
hg clone remote Dir
To initialize new mercurial repository in current directory:
hg init
Begin tracking all files
hg add
Begin tracking file test
hg add test
Stop tracking and delete file test
hg remove test
Make commit with message to current repository
hg commit -m "message..."
Show history of changes
hg log
Show status of files
hg status
See who changed, what changed and when
hg annotate file
Lists known remote Repos
hg paths
Lists tracked file changes
hg diff
List changes to test file
hg diff test
List changesets available at remote
hg incoming
Pull all new changesets into local, but does not update work tree
hg pull
Pull all new changesets into local, and update work tree
hg pull -u
Merge working directory with another revision
hg merge
Undo all uncomm­itted changes
hg revert
Push changesets to remote
hg push
To create a new named branch
hg branch feature

GHCi runtime linker found a duplicate definition error

Today I started to play with attoparsec package and tried to write simple parser. I wrote really toy data type like this:

I tried to type:
*SimpleParser> End
in ghci and will get End as I expected. Instead End I got following error:

As we can see in error output GHCi runtime linker found duplicate definition of _hs_bytestring_long_long_uint_hex. Let's see what's wrong bytestring package with:
cabal info bytestring
It will give us output like this:

We can note that there two installed versions of bytestring package. Let's remove old version with:
sudo ghc-pkg unregister --force bytestring-
That's all. After this error with GHCi runtime linker found a duplicate definition error...... will disappear. Hope this blog post will be useful for all who will meet error like this. Happy coding!