Finally, if you still want to try this crazy idea and write something in
assembly (if you've reached this section -- you're real assembly fan),
I'll herein provide what you will need to get started.
As you've read before, you can write for Linux in different ways;
I'll show example of using pure system calls.
This means that we will not use libc at all, the only thing required for
our program to run is kernel.
Our code will not be linked to any library, will not use ELF interpreter --
it will communicate directly with kernel.
I will show the same sample program in two assemblers, nasm and gas,
thus showing Intel and AT&T syntax.
First of all you need assembler (compiler): nasm or gas.
Second, you need linker: ld, assembler produces only object code.
Almost all distributions include gas and ld, in binutils package.
As for nasm, you may have to download and install binary packages
for Linux and docs from the
nasm webpage;
however, several distributions (Stampede, Debian, SuSe)
already include it, check first.
If you are going to dig in, you should also install kernel source.
I assume that you are using at least Linux 2.0 and ELF.
Linux is 32bit and has flat memory model.
A program can be divided into sections.
Main sections are .text for your code,
.data for your data, .bss for undefined data.
Program must have at least .text section.
Now we will write our first program. Here is sample code:
NASM (hello.asm)
section .data ;section declaration
msg db "Hello, world!",0xa ;our dear string
len equ $ - msg ;length of our dear string
section .text ;section declaration
;we must export the entry point to the ELF linker or
global _start ;loader. They conventionally recognize _start as their
;entry point. Use ld -e foo to override the default.
_start:
;write our string to stdout
mov edx,len ;third argument: message length
mov ecx,msg ;second argument: pointer to message to write
mov ebx,1 ;first argument: file handle (stdout)
mov eax,4 ;system call number (sys_write)
int 0x80 ;call kernel
;and exit
mov ebx,0 ;first syscall argument: exit code
mov eax,1 ;system call number (sys_exit)
int 0x80 ;call kernel
GAS (hello.S)
.data # section declaration
msg:
.string "Hello, world!\n" # our dear string
len = . - msg # length of our dear string
.text # section declaration
# we must export the entry point to the ELF linker or
.global _start # loader. They conventionally recognize _start as their
# entry point. Use ld -e foo to override the default.
_start:
# write our string to stdout
movl $len,%edx # third argument: message length
movl $msg,%ecx # second argument: pointer to message to write
movl $1,%ebx # first argument: file handle (stdout)
movl $4,%eax # system call number (sys_write)
int $0x80 # call kernel
# and exit
movl $0,%ebx # first argument: exit code
movl $1,%eax # system call number (sys_exit)
int $0x80 # call kernel
Second step is producing executable file itself from object file, by invoking linker:
$ ld -s -o hello hello.o
This will finally build hello ELF binary.
Hey, try to run it... Works? That's it. Pretty simple.
If you get interested and want to proceed further,
you may want to look through
Linux assembly projects,
they contain PLENTY of source code and examples.