Manually Creating an ELF Executable
robinhoksbergen.com
robinhoksbergen.com
All the same, very cool, this is a great experiment for anyone to work on :)
True, I needed 62 bytes to get the greeting in there.
But hand assembly isn't so far away from our experience. Woz famously wrote the original Apple ][ ROM by hand, including the BASIC interpreter (itself written in a "SWEET16" bytecode for which he hand-assembled the interpreter). I don't know what the tooling looked like for that; surely he wasn't hand-toggling this thing in every time. Presumably the monitor and casette interface were written first...
Challenge accepted.
b409ba0d01cd21b44cb05dcd2148454c4c4f20574f524c442124
Here's the breakdown: b409 MOV AH, 09h ; OUTPUT string
ba0d01 MOV DX, 010Dh ; address of output buffer (remember we're loaded into 0100h)
cd21 INT 21h
b44c MOV AH, 4Ch ; TERMINATE with return code
b05d MOV AL, 5Dh ; return code
cd21 INT 21h
48454c4c4f20574f524c442124 "HELLO WORLD$" ; DOS strings are $ terminated
Back in the day we used to do this with the DEBUG.COM command. It's actually not that bad to do this. The thing that sucks is hand assembling and going back to fixup your addresses. It starts to get hairy if you need to flip around the CS and DS registers to shift in different segments.As an exercise for the reader use the RET instruction instead of doing the return code stuff. If you want to really get into you you can look up how to read from the console and then display that string back to the user.
The way this works is pretty clever - the COM loader places an INT 20h instruction (the old-style terminate function) at offset 0 in the PSP (the 100h-byte-long structure loaded right before the contents of the COM file). The loader also sets up the word above the initial stack pointer to 0 so that a RET will return to address 0 and execute the INT 20h.
b013cd10c52f0f3197b18cb38cfe018009804b75f881c74001e2f0ebe9
I made this in 2001 and used it once in a job interview, I asked for access to a computer running XP, opened cmd.exe and debug.exe, entered the asm code (rdtsc is not supported by debug.exe but i remembered the 0f31 opcode) and blew someones mind.edit: You're probably thinking it should be placed as an immediate value. It's hard to say exactly how many bytes it'd take up that way, so using an address to an immediate value is a bit simpler.
The movzx/movsx is only needed when you're doing something like movzx EAX, BX. That way you're sure the CPU does what you expect when moving from a smaller register to a larger one. Man do I hate x86.