So it suddenly occurs to me that I have a pending #assignment on by Operating Systems course. The assignment seems to be trivial: it is to create a bootloader which prints 'Hello World' on the console. Thought it would be interesting to understand this with some help from my mastodon folks
#university #operatingsystems #bootloader #nasm #assembly
PS: future me, if you happen to be reading this post after you have forgotten about this, you can thank me later.
Here is the code after a bit of good formatting(?) but at least its more readable. I have a lot of questions, but we will go through it line by line.
@srevinsaju I called them routines, or sometimes subroutines. Procedure is jargon from early procedural languages, such as Pascal.
@codewiz Ah names are really confusing, most of my professors and books refers to them as “procedures” :/
@srevinsaju Ok, there's no official naming convention, but this is how early programming languages progressed:
ROUTINE: a block of instructions that accomplishes a task. You can JMP to it and it doesn't necessarily return (e.g.: "the init routine jumps to the loader routine, which jumps to the main screen routine...")
SUBROUTINE: a routine designed to be called from multiple locations and return to the caller.
Late 1970s CPU designs supported this programming model by adding a stack pointer register (SP) and dedicated opcode pairs like JSR/RTS (m68k) and CALL/RET (x86).
PROCEDURE: ALGOL 60, the precursor of all modern procedural languages, including C, introduced the concept of passing arguments to subroutines. Argument passing used the awkward "call-by-name", but the VALUE keyword let you override it. There were no pointers and no references yet.
Modern calling conventions pass the first N arguments in registers, and push the rest on the stack. This is what you'd use in your 8086 asm.
FUNCTION: Lisp was ahead of its time, with first-class functions in the '60s.
My first encounter with functions was in BASIC. The Commodore dialect had built-in functions such as SIN(X), and supported a limited form of user-defined functions with a single argument and a one-line expression:
DEF FN TRIPLE(X) = X*3
Calls could nest:
PRINT FN TRIPLE(FN TRIPLE(5) + 1)
Pascal had an explicit distinction: functions are procedures which return a result.
K&R C didn't bother with procedures: everything is a function, and if you omit return at the end, it will return garbage to the caller
Later, ANSI C added the "void" type and (optional) function prototypes, making this footgun somewhat less dangerous.
Support for declaring and defining functions without a full prototype will be finally removed in C23:
https://en.cppreference.com/w/c/23