The shoutbox is currently out of service. Join us on Discord instead.
You can help CodeWalrus stay online by donating here.

scas - a new assembler & linker

Started by SirCmpwn, April 07, 2015, 04:07:31 am

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

SirCmpwn

scas is the assembler and linker that we've been working on to replace sass for KnightOS. It also works great for TIOS. Here's the rundown of what makes it interesting:


  • Separate assembly and linking steps

  • ASxxxx compatibility (which means SDCC support)

  • Runs on any POSIXish system (plus Windows)

  • Detailed documentation and Unix style design

  • Clean and maintainable codebase

  • KEXC, 8xp, and binary output supported



scas is not complete, but the list of features above is working. I can explain in detail why each of those features is important.

Separate assembler and linker
This is really long so I put it in a spoiler tag:
Spoiler: ShowHide

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:
    call subroutine
    ret


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
    call subroutine


This works even if you delete main.asm. scas includes a source map in object files. You can see it with scasdump:

[email protected] /t/tmp.kU6Nr9sNGD> scasdump -s -r -c main.o
Area '_CODE'
Source file 'main.asm'
  [0x0000:03] main.asm   main:
  [0x0000:03] main.asm:2          call subroutine
  [0x0003:01] main.asm:3          ret
Symbols defined:
  'main' == 0x00000000 (Label)
Unresolved references:
  [0x0001] 'subroutine'


This behaves similarly to objdump on Unix systems. I can now write another small file:

subroutine:
    ld hl, 0
    ret


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
subroutine:
    ld hl, 0
    ret

main:
    ret


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

main:
    call subroutine
    ret


...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.


ASxxx compatability
scas is the basis of KnightOS's C support, when combined with kcc (our fork of SDCC). With this, you can write C programs that run on KnightOS. You can probably ALSO write C programs that run on TIOS with scas! More on that soon.

POSIXish support
scas is officially supported on Linux, OSX, Windows, BSD, and BeOS (Haiku). It'll run on just about anything that supports a handful of POSIX functions. You could probably port it to ndless if you wanted, too. Unfortunately it's not likely to run on KnightOS itself, due to size constraints.

Detailed documentation etc
If you're on a Unix system, you'll appreciate the fact that scas has a nice set of man pages. If you're on Windows, you'll appreciate the fact that everyone else has a nice set of man pages to read. The code base is also really clean and easy to get into, unlike basically every other assembler.

KEXC, 8xp, and binary output
scas natively supports KEXC (the KnightOS executable format), 8xp (the TIOS executable format), and straight up binary. Example:

scas -fformat=8xp -f8xp-name=SOMENAME -f8xp-protected=yes [rest of args]

Conclusions
scas is shaping up to be the best assembler (and linker) for z80 out there. I really like it. It's not completely done yet, but you can probably start using it for your projects now (several people in the KnightOS community are) so long as you're okay with the occasional breakage. I'll keep you guys updated on progress.

https://github.com/KnightOS/scas

One of the things KnightOS tries to do is not only make an OS for calcs, but improve the tooling we have for calculators even outside of KnightOS. scas is part of that mission.

Snektron

Cool :) Though i can't build it myself and the version you gave me doesn't work :/
Legends say if you spam more than DJ Omnimaga, you will become a walrus...


Duke "Tape" Eiyeron

Nice work! Does it support gcc's object file? (Just for curiosity)

SirCmpwn

Quote from: Duke "Tape" Eiyeron on April 07, 2015, 11:44:49 am
Nice work! Does it support gcc's object file? (Just for curiosity)


No. We have a different object file format (elf is ill suited to 8-bit CPUs). Our object format is documented here:

https://github.com/KnightOS/scas/blob/master/doc/sobj

Duke "Tape" Eiyeron

As I said, it was by curiosity. and gcc seems to let executable with a consequent size most of the time...

SirCmpwn

Quote from: Duke "Tape" Eiyeron on April 07, 2015, 03:27:40 pm
As I said, it was by curiosity. and gcc seems to let executable with a consequent size most of the time...


The question did not upset me. What do you mean by a "consequent size"?

Duke "Tape" Eiyeron

I remembered seeing full fledged C compilers which outputted (very) smaller object files from the same sources than GCC.

SirCmpwn

Quote from: Duke "Tape" Eiyeron on April 07, 2015, 03:31:27 pm
I remembered seeing full fledged C compilers which outputted (very) smaller object files from the same sources than GCC.


I see. That's not entirely relevant to how scas works - scas is an assembler for z80, which is an 8-bit CPU. gcc mainly targets i686 (or x86/amd64), which is 32 to 64 bits. The object format gcc/gas/gold uses is ELF, which is well suited to such architectures. scas uses SCASOBJ, which is better suited to 8-bit architectures (and is actually flexible enough to support any width of arch up to 64, fwiw). ELF only (according to the spec, at least) supports 32 and 64 bit architectures, and uses data structures that are more difficult to implement on an 8 bit architecture, and as such I didn't think it was a good idea to use ELF. That being said, I just recently built some abstractions around the code for generating output files and adding ELF support is probably possible if you truly desire it.

Powered by EzPortal