Could anyone help me write the equivalent of the program below so it works on the online IDE at https://www.mycompiler.io/new/asm-x86_64? I am a teacher and want to show my students so real working assembly so they stop thinking Little Man Computer is real. I just don't have time right now to work it out for myself!
section .text
global main
extern printf ; the C function to be called
main:
mov eax, 45
mov ebx, 55
add eax,ebx
push eax
push message
call printf
add esp, 8
ret
message db "Value = %d", 10, 0
https://www.mycompiler.io/new/asm-x86_64 apparently doesn't link libc for asm, so you can only use Linux system calls directly (via syscall
), not libc functions like printf.
https://www.onlinegdb.com/ has asm, but only GCC (GAS), not NASM. Still, you can use .intel_syntax noprefix
to get GAS's MASM-like Intel syntax. Crucially, it does have a working GDB setup that lets you single-step your asm and see register values. This is nearly essential for learning asm: many kinds of mistakes lead to exactly the same error (segfault, or no output), and these are mistakes the assembler won't diagnose. Learning asm without a debugger is like trying to build a robot while blindfolded (or other colourful analogies).
Seeing exactly what each instruction did is exactly how you should be thinking about asm, especially when trying to understand why your program didn't do what you hoped.
If you did want to use that specific IDE (mycompiler.io) without libc, How do I print an integer in Assembly Level Programming without printf from the c library? has code that turns an unsigned integer into a decimal ASCII string and feeds it to an x86-64 Linux write
system call with rax=1
/ syscall
.
extern exit
lets call exit
assemble but not link, as a quick test: undefined reference to 'exit'
.
There's also https://tio.run/ which has NASM and FASM, as well as GAS. FASM allows making 32-bit code via having FASM make an executable directly (format ELF executable 3
) instead of a .o
which TIO.run expects to be able to link into a 64-bit executable. I've used that to test some code-golf answers (like this) where I specifically wanted 32-bit mode, not 64-bit, so I could use dec edi
on a pointer without needing a REX prefix.
I notice that you're using a 32-bit stack-args calling convention for your attempt to call printf. That's not how the x86-64 System V ABI works (What are the calling conventions for UNIX & Linux system calls (and user-space functions) on i386 and x86-64), so make up your mind whether you want to teach 32-bit code (which has a simpler but worse calling convention, and almost everything can be 32-bit), or x86-64 where normal code often takes advantage of 32-bit operand-size and the implicit zero-extension to 64-bit. And where args are passed in registers, to system calls with a similar calling convention to function calls.
related: 32-bit Hello, world in assembly language with Linux system calls? with int 0x80
system calls and lots of explanation.
Also, you don't want to use int 0x80
in 64-bit code: What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code?