Tuesday 27 September 2011

Small steps in assembly

The first thing most people really want to do in assembly is connect it to normal C code (or the high level language of your choice).  Assembly is all well and good, but no one wants to rewrite the OS (unless you do...in which case there are many other places you should be heading to).

Let's start then with two straight forward programs.  One piece of assembly we can call from C, and one that is the main program and that then calls a C function.

Calling Assembly from C
The first piece of C code looks very simple, namely:
#include <stdio.h>

extern    int    assemAdd( int input );

void main( void )
{
    printf( "%d\n", assemAdd( 57 ) );
}
assemAdd.c

This piece of code simply calls an external function - namely assemAdd - which we'll implement in assembly. It passes 57 to the function and prints the result.

Let's have a look at the assembly code:
global    _assemAdd

section .text

_assemAdd:
    mov    eax, [ esp + 4 ]
    add    eax, 5
    ret
assemAdd.s

We'll go through what the assembly code does line by line in detail next time (mainly because I'm going to have to discuss calling conventions), but we'll get this built and check the outcome.

Here's how we build these file and run the resulting executable:
$ nasm -f win32 assemAdd.s
$ gcc assemAdd.c assemAdd.obj -o assemAdd.exe
$ ./assemAdd.exe
62
$

The first line assembles the assemAdd.s file into the win32 format (because we're running this on Windows). This will produce an assemAdd.obj file.

The second line will compile the assemAdd.c file, and link the resulting object file with the assemAdd.obj file created by nasm.

It then creates the assemAdd.exe executable, which we run and see our output. As I said, we'll be going through this in detail next time, but see if you can work out what's happening on your own.

Calling C from Assembly
In this example we're going to create an assembly program that calls one of the libc methods - namely printf. Again, we'll go into detail next but for now we'll get something working:
global    _main

extern    _printf


section    .data

printStr:    
    db    'This is a test print', 0

section .text

_main:
    push    ebp
    mov     ebp, esp
    push    printStr
    call    _printf
    leave
    ret
assemMain.s

Now, if we assemble this using nasm we can link it using gcc. Gcc, by default, will automatically include libc into the build unless told not to, so we don't have to do anything complicated:
$ nasm -f win32 assemMain.s
$ gcc assemMain.obj -o assemMain.exe
$ ./assemMain.exe
This is a test print
$

So, there we go. We'll dig into things a little deeper next time (including explaining why assembly functions have a preceding '_') but for now we've managed to get some code built and working. Which is always a good place to start from!

No comments:

Post a Comment