To run Hello World we just need to issue two system calls: One to print the string and the other to exit nicely.
Here is the src file you need hello-world.S
We typically use file suffix .s for assembler when machine generated. The capital .S is used for lovingly hand-crafted assembler files.
Contents of hello-world.S
# Hello World (C) 2010 D J Greaves, University of Cambridge Computer Laboratory .text .globl _start _start: mov $0x1,%edi # File descriptor no (stdout = 1) lea hello(%rip), %esi # String mov $0x6,%edx # 6 chars mov $1,%eax # sys call number. 1 = write syscall mov $0x11,%edi # return code mov $60,%eax # sys call number. 60 = exit syscall hello: .string "Hello!" # eof
We must first assemble the file.
djg>$ as -o hello-world.o hello-world.S djg>$ ls -l -rw-rw-r-- 1 djg11 djg11 768 Oct 23 09:29 hello-world.o -rw-rw-r-- 1 djg11 djg11 425 Oct 23 09:27 hello-world.S
To get a linux executable, we can run it through the linker. Just running "chmod +x" on the assembler output is not sufficient. Why?
djg>$ ld hello-world.o djg>$ ls -lt -rwxrwxr-x 1 djg11 djg11 4736 Oct 23 09:30 a.out -rw-rw-r-- 1 djg11 djg11 768 Oct 23 09:29 hello-world.o -rw-rw-r-- 1 djg11 djg11 425 Oct 23 09:27 hello-world.S
Now we can execute it natively and under strace:
djg>$ ./a.out Hello!djg>$ djg>$ strace ./a.out execve("./a.out", ["./a.out"], 0x7fffdfb599b0 /* 41 vars */) = 0 write(1, "Hello!", 6Hello!) = 6 exit(17) = ? +++ exited with 17 +++ djg>$
strace reports the system calls invoked.
A successful program exits with return code 0 by convention. Here we deliberately returned 17 (0x11), which is non zero, to show how the shell reports it.
We can look at the generated code using a disasembler, such as objdump -d
djg>$ objdump -d hello-world.o hello-world.o: file format elf64-x86-64 Disassembly of section .text: 0000000000000000 <_start>: 0: bf 01 00 00 00 mov $0x1,%edi 5: 8d 35 18 00 00 00 lea 0x18(%rip),%esi # 23b: ba 06 00 00 00 mov $0x6,%edx 10: b8 01 00 00 00 mov $0x1,%eax 15: 0f 05 syscall 17: bf 11 00 00 00 mov $0x11,%edi 1c: b8 3c 00 00 00 mov $0x3c,%eax 21: 0f 05 syscall 0000000000000023 : 23: 48 rex.W 24: 65 6c gs insb (%dx),%es:(%rdi) 26: 6c insb (%dx),%es:(%rdi) 27: 6f outsl %ds:(%rsi),(%dx) 28: 21 00 and %eax,(%rax) djg>$ objdump -d a.out a.out: file format elf64-x86-64 Disassembly of section .text: 0000000000401000 <_start>: 401000: bf 01 00 00 00 mov $0x1,%edi 401005: 8d 35 18 00 00 00 lea 0x18(%rip),%esi # 401023 40100b: ba 06 00 00 00 mov $0x6,%edx 401010: b8 01 00 00 00 mov $0x1,%eax 401015: 0f 05 syscall 401017: bf 11 00 00 00 mov $0x11,%edi 40101c: b8 3c 00 00 00 mov $0x3c,%eax 401021: 0f 05 syscall 0000000000401023 : 401023: 48 rex.W 401024: 65 6c gs insb (%dx),%es:(%rdi) 401026: 6c insb (%dx),%es:(%rdi) 401027: 6f outsl %ds:(%rsi),(%dx) 401028: 21 00 and %eax,(%rax) djg>$
Can we see any differences between the input and the output? We see the linker has relocated using a default origin. We see it does not understand ASCII and has dissassembled "hello" as machine instructions!
(C) DJ Greaves 2010.