This is the most important feature. It means that you can compile your assembly into an "object file" and then combine object files into a binary later. For example, let's say I do this:main:
I can run this file (as-is) through scas like so:scas -c -o main.o main.asm
This will produce "main.o" without errors. However, if I try this:scas -o main.bin main.o
It will give the following error:main.asm:2:0: error #5: Unknown symbol
This works even if you delete main.asm. scas includes a source map in object files. You can see it with scasdump:sircmpwn@homura /t/tmp.kU6Nr9sNGD> scasdump -s -r -c main.o
Source file 'main.asm'
[0x0000:03] main.asm main:
[0x0000:03] main.asm:2 call subroutine
[0x0003:01] main.asm:3 ret
'main' == 0x00000000 (Label)
This behaves similarly to objdump
on Unix systems. I can now write another small file:subroutine:
ld hl, 0
And compile it like so:scas -c -o subroutine.o subroutine.asm
This produces another object file, subroutine.o. You can now run this without errors:scas -o main.bin main.o subroutine.o
This "links" together the two object files. Since subroutine.o defines "subroutine", the reference from main.o works and it's all good. Of course, this is all optional. The following works, too:scas -o main.bin main.asm subroutine.asm
Or even this:scas -o main.bin main.asm subroutine.o
Or just this:scas main.asm
Which assumes you want the output file to be main.bin.
This is all important because it lets you compile each of your files and then link them all separately. This means that if main.asm changed but subroutine.asm didn't, only main.o would need to be recompiled and then it could be linked against the old subroutine.o. For smaller projects, this isn't a big deal, but it saves a lot of time on larger ones. You could also swap out a different version of subroutine.o so long as it also provided the "subroutine" label by simply linking against a different object file. This gets even cooler when you start thinking about static linking. KnightOS has a libc
that provides a bunch of common functionality. You can link against it and scas will optimize out the things you don't use. This lets you build libraries that are compiled into your programs rather than used separately. As an added bonus, you can choose to use the explicit export option. That way, you can write subroutine.asm like so:.export subroutine
ld hl, 0
When you link against main.o, you won't get an error for duplicate labels. This is because only "subroutine" is exported from this object. This lets you reuse common label names and write each file as its own module without worrying about conflicting with other modules. If you want to get really crazy, you can also use the explicit import flag, which would make you change main.asm to this....import subroutine
...to avoid a compiler error. This is starting to get really similar to how C works, right? scas uses a very similar design to modern toolchains.