When do you ever need assembly?
Tags: assembly, lowlevel
Published: 2019-12-01 01:06:37

---
title: When do you ever need assembly?
published: true
description: 
tags: assembly, low-level
---

If the objective of your application is to print to screen, there are better ways to achieve it. Assembly is the least qualified language for the job. Below are just few examples to demonstrate this.

Python
```python
print("Hello world")
```

Go
```Go
import "fmt"
func main() {
    fmt.Println("hello world")
}
```

C#
```C#
using System;
public class HelloWorld
{
   public static void main(String[] args)
   {
       Console.WriteLine("HelloWorld!");
   }
}
```

C++
```C++
#include<iostream>    
using namespace std;
int main() 
{
    cout<<"Hello World";      
    return 0; 
}
```

Hardly 7 lines of code even for C++. If like me you've ever wondered what happens under the hood, read on. What if the above language API's were not available? What if all you had were registers, Memory, Operating System (OS) and Assembly compiler and linker. For simplicity this will be a Intel-based X-86 Unix System.

Lets start with basics, how would you print a character to screen?
We will have make use of the kernel services which in-turn interfaces with the hardware. These services are available as subroutines called syscalls and are invoked by raising events called interrupts. When an interrupt is raised,
program execution is paused and  control is transferred to the CPU which reads specific registers to determine the action to take, after which program execution resumes where it left of. 

Of the different [syscalls](https://www.tutorialspoint.com/assembly_programming/assembly_system_calls.htm), of interest to us is the one that displays characters to the monitor: sys_write. To invoke this, **eax** register has to have 4(system call number), **ebx** register has to have 1 to specify stdout output, the address of word to be written need be placed in **ecx** register and the length of the word need be in register **edx**. The problem is now simple enough; define the string, place it's address in **ecx**, place its length (13) in **edx**, place 4 in **eax**, place 1 in **ebx** then raise an interrupt. The program below should do the trick. 

```asm
section	.text        ; sections required for 
   global _start     ;must be declared for linker (ld)
	
_start:	            ;entry point marker, required for linker
   mov	edx,len      ;message length
   mov	ecx,msg     ;message to write
   mov	ebx,1       ;file descriptor (stdout)
   mov	eax,4       ;system call number (sys_write)
   int	0x80        ;call kernel
	
   mov	eax,1       ;system call number (sys_exit)
   int	0x80        ;call kernel

section	.data
msg db 'Hello, world!', 0xa  ; string to be printed followed by newline
len equ $ - msg     ;gets length of the string and stores it in variable len
```

This does the job, but still raises questions, it almost seems as if the invoked functions and interrupts have magic. If CPU's work with bits, how does it print strings? After an interrupt, how does the CPU where to resume to? How would this change if the registers were 16 bit wide? These are valid questions that should probably be addressed in another post. A major concern you may have as a high-level language developer is why do this at all? High-level languages exist for good reason; to increase developer's productivity, allow them to focus on business logic instead of registers.

Correct! We shouldn't be writing applications in assembly, but we should know about language internals. I've learnt a thing or two just from the above example. 
Look at Java snippets below.

```Java
System.out.println("**************")
System.out.println("Welcome user!")
```

```Java
System.out.println("**************\nWelcome user!")
```
Two ways of achieving the same objective, but after reading assembly above, I'm inclined to prefer the latter snippet. In the absence of compiler optimization, the second program will be more performant because it requires only one interrupt to write to screen. For each interrupt, the CPU has to save context to Stack, perform a syscall, then resume context; the less it happens, the faster the program. Performance may not be important if the block is not called often but it is a major problem if it is called in a loop or responds to frequent requests or worse responds frequently in a loop.

Do you need assembly for your job? Probably not. Will it make you more productive? Hard to say. Will it make you a better developer? Absolutely yes! Happy hacking!