3 ms·
nasm cannot generate ELF binaries directly, only .o files which must be formally linked. So you have to use `ld` on the generated object file(s) to produce a bi
by exikyut 9y ago
nasm cannot generate ELF binaries directly, only .o files which must be formally linked. So you have to use `ld` on the generated object file(s) to produce a binary. (I've not (yet) tested using LLVM's new linker or the linker stages from other compilers.)
Some extremely anecdotal and unscientific testing I did a little while back seemed to show that fasm's "hello world" example is several scales smaller than nasm's. I decided to be scientific and re-do my test with similar programs.
fasm includes a hello-world program in the distribution:
format ELF64 executable 3
segment readable executable
entry $
mov edx, len
lea rsi, [msg]
mov edi, 1
mov eax, 1
syscall
xor edi, edi
mov eax, 60
syscall
segment readable writeable
msg db 'Hello world!', 10
len = $ - msg
Here I pretty much converted the fasm example to match nasm as closely as possible (using various online references to get an idea of how it should look for nasm):
section .text
global _start
_start:
mov edx, len
mov rsi, msg
mov eax, 1
mov edi, 1
syscall
xor edi, edi
mov eax, 60
syscall
section .data
msg db "hello, world!", 10
len equ $ - msg
What isn't really possible with nasm is to remove the symbol table and _start export. This makes a phenomenal difference in file size.
Here's nasm:
$ ls -lh nasm64 nasm64.o
-rwxr-xr-x 1 i336 users 512 Oct 9 10:10 nasm64
-rw-r--r-- 1 i336 users 880 Oct 9 10:10 nasm64.o
Because fasm doesn't need to mess around with exports or symbols and can just write binaries directly, it absolutely kills nasm:
$ ls -lh hello64
-rwxr-xr-x 1 i336 users 222 Oct 9 10:29 hello64
One of my major interests in assembly language is in having tight control over output file size, so fasm is super interesting to me.
I am very curious as to the file format differences though. Apparently nasm generates SYSV-format ELF files, while fasm generates a Linux-specific variant...?
$ file nasm64
nasm64: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, stripped
$ file hello64
hello64: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, stripped
That's interesting. I'm genuinely curious what this means.
As far as the size differences are concerned, http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html http://www.muppetlabs.com/~breadbox/software/tiny/teensy.htm... shows that to make smaller stuff than ld generates, you have to start hand-composing the ELF file. So fasm is pretty much the only way to produce the smallest ELFs with minimal fuss on Linux.
- chaosite 9y agoFile isn't smart enough to read too much into the actual ELF format, all it's doing is parsing part of the header. What that difference means is that fasm put a 3 in byte 7 of the header, while nasm put a 0 there. And apparently putting a 0 there no matter what the target OS ABI is common practice. https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header https://en.wikipedia.org/wiki/Executable_and_Linkable_Format...
- exikyut 9y agoOh! I see! Thanks so much for this little detail - you helped me figure out that in the format ELF64 executable 3 at the top, that 3 is what gets put into the binary! Change it to 0, and sure enough it shows as SYSV. That is cool. ...change it to 2 and it shows as NetBSD ...and 1 makes it show as HP-UX ...4 makes GNU/Hurd O.o 5 is 86Open 6 is Solaris WAT 7 is "Monterey"?!?! (Yup, still executes just fine) 8 is IRIX 9 is FreeBSD 10 is Tru64 O.o 11 is Novell Modesto 12 is OpenBSD 13 and 14 don't display anything, and I presume that's because that's where this madness ends. That was extremely interesting...
- xelxebar 9y agoI've hand-written a couple elf binaries just for kicks. The wikipedia page on ELF has a list of current conventions on the 7th byte in the elf header (e_ident[EI_OSABI] in the spec) [1]: 0x00 System V 0x01 HP-UX 0x02 NetBSD 0x03 Linux 0x04 GNU Hurd 0x06 Solaris 0x07 AIX 0x08 IRIX 0x09 FreeBSD 0x0A Tru64 0x0B Novell Modesto 0x0C OpenBSD 0x0D OpenVMS 0x0E NonStop Kernel 0x0F AROS 0x10 Fenix OS 0x11 CloudABI 0x53 Sortix I don't know enough about linker/loader details, though, to tell you how different ones actually make use of this information. IIRC, the glibc loader just checks that it's 0x0 or 0x3 and leaves it at that. [1] https://en.wikipedia.org/wiki/Executable_and_Linkable_Format https://en.wikipedia.org/wiki/Executable_and_Linkable_Format