- Using segments offloads program code management to dedicated tools.
- Not using segments replaces these tools by the a programmer doing everything by hand.
While the difference may not be a big one with short programs, it gets relevant soon.
Segments are a way to organize code and/or data on a logical level. Segments group sections of code and/or data according to their use. When grouped, they can be used to assign meta-attributes needed to manage the program.
The basic organization of C (Unix) programs as three segments is a great example here.
- TEXT - collects all executable data (code).
- DATA - all non executable data fields (with predefined values)
- BSS - joins all uninitialized data.
By assigning everything a program source generates during compilation to either segment, it allows the linker, as first step, to combine all chunks of each kind into a single element and adjust all addresses accordingly. The loader, as next stage, can place these unified blobs into memory and, if supported by architecture, for example set executable (TEXT) or non-executable (DATA) flags for protection. Similar it can enable write protection for code and so on.
So again, segments are about two basic mechanics:
- grouping code/data
- assigning attributes to these groups.
Of course, with rather simple programs, like the example given, without much structure, the grouping doesn't give much support. Similar, with rather simple systems like a bare 6502, there isn't much management that could be simplified by segments.
Still, even with a 6502, complex structures can be build, where usage of segments will simplify management - and more important reduce chance of programming errors.
Imagine a game, for example for an Atari VCS 2600; as soon as this project goes beyond basic PONG, it will outgrow the 4 KiB ROM space the console offers. So the game needs to be split into multiple code chunks that get paged in and out depending on program flow (essentially overlays). All of them will reside at the same address as viewed from the CPU, but different addresses within the ROM chip.
Such a program may of course still be handled the 'simple way' of our second example (without segments). But to do so, the whole project must reside in a single source file. Or at most, it can be split at physical addresses. One must keep very fine track of what to put where.
With segments, code can be structured (almost) freely, as they tell the linker how to join the various pieces, each compiled separately, into a single binary. In our example, one would simply define a segment name for each ROM page (like PAGE1/2/3/etc.). When writing code intended to go into page 1, it simply gets prefixed by
.segment "PAGE1" (CA65 syntax). After that, the linker will take care of grouping all code for page 1 together, no matter in what source file it was written or compiled from and in which sequence. The programmer becomes free to organize source in a manner reflecting the way the game is organized, while compiler/linker/loader takes care of putting it into the sequence the computer needs to see it. The linker will also report when a segment outgrows the available space, so no-one has to count bytes by hand. After all, isn't the whole purpose of using tools, like an Assembler, to offload the grind to the computer, so the programmer can focus on the problem?
The same issue comes, BTW, as well up on larger 6502 systems than a VCS. Like having even more complex programs that outgrow even a 64 KiB RAM - or need to be shrunk by modularisation to keep some RAM free for user data. :))
Of course, more sophisticated usage also needs more sophisticated tools. XA65 is here rather on the simple side. CA65 in turn is quite capable of handling complex linking situations - which as well means it needs a bit more time to discover how to do it.
Bottom line, like any other management tool, segments shine with increasing complexity of the task to be done.