[cc65] Forced imports by linker config

From: Ullrich von Bassewitz <uz1musoftware.de>
Date: 2010-11-12 15:52:54
I reworked linker config parsing and processing, so it is now possible to
force imports of symbols by using the linker config. The code needs some
testing, but it looks very promising. This means that the conceptual model
used currently can be changed: It is no longer the compiler that must force
the import of startup code, this can be done in the linker. Using this method,
the linker config can also define, which headers get included in the output
file(s).

So as an example, normal C programs or C programs that are loaded elsewhere
and started using SYS (on the Commodores, that is) can be created with a
simple change in the linker config. It is no longer necessary to change the
startup code.

Please note that the old syntax for the SYMBOLS section ("symbol = value") is
gone. Attributes are used instead as with the other sections in the config
file.

To make the above possible, I had to change the evaluation of expressions used
in the linker config. Before, they were handled specially and had a constant
value as a result. Because this did no longer work when reading the config and
processing it at a later time, I had to make the expressions "normal"
expression trees as they're also used in the assembler and object files.

This has far reaching consequences. Actually the consequences may be even
greater than the ones from adding forced imports. Since the start address and
size of a memory area is now an expression that is parsed but evaluation is
delayed until its value is needed, it is now possible to use other symbols in
these expressions. These other symbols may be the start address or size of
another memory area already defined before, or exported symbols from any of
the object files. This allows to do so complicated things that I'm not even
able to guess what is finally possible:-)

A few of the easier examples: One can make a memory area variable sized
depending on the size of the memory area before it:

---------------------------------------------------------------------------
MEMORY {
    ZP:     file = "", define = yes, start = $0002, size = $001A;
    HEADER: file = %O, define = yes, start = $07FF, size = $000E;
    RAM:    file = %O, define = yes,
            start = __HEADER_START__ + __HEADER_SIZE__,
            size = $D000 - __HEADER_START__ + __HEADER_SIZE__;
}
---------------------------------------------------------------------------

A memory area can also have a size that is defined somewhere in an object
file:

---------------------------------------------------------------------------
header.s:
        .export         HEADERSIZE = .sizeof(Header)
        .segment        "HEADER"
        Header:         .addr   *+2
---------------------------------------------------------------------------
SYMBOLS {
    HEADERSIZE:  type = import, addrsize = absolute;
}
MEMORY {
    HEADER: file = %O, define = yes, start = $07FF, size = HEADERSIZE;
}
SEGMENTS {
    HEADER:   load = HEADER, type = ro;
}
---------------------------------------------------------------------------

Or we can place a memory area inside a buffer that is defined in an assembler
module:

---------------------------------------------------------------------------
drivebuf.s:
        DriveBuffer:    .res    256
        .export         DriveBuffer
        .export         DriveBufferSize = .sizeof (DriveBuffer)
---------------------------------------------------------------------------
SYMBOLS {
    DriveBuffer:     type = import, addrsize = absolute;
    DriveBufferSize: type = import, addrsize = absolute;
}
MEMORY {
    RAM:         file = %O,           start = $800, size = $D000;
    DRIVEBUFFER: file = "driver.bin", start = DriveBuffer, size = DriveBufferSize;
}
SEGMENTS {
    CODE:       load = RAM,         type = ro;
    RODATA:     load = RAM,         type = ro;
    DATA:       load = RAM,         type = rw;
    BSS:        load = RAM,         type = bss, define = yes;
    DRIVERCODE: load = DRIVEBUFFER, type = ro;
}
---------------------------------------------------------------------------


The changes had some effects on order of command line arguments, so it may be
necessary to change make- or batch processing files. For examples, the output
file (-o switch) must now be defined before using -t or -C, because the config
file is read when -t or -C is found on the command line. Changing the output
file name using -o when the config is already read will cause the name be
ignored in most cases. The same is true for -t/-C and libraries: If your
config has forced imports, it must be read before any libraries, because
otherwise the import may not be resolved.

Please let me know if there are any problems with the new code.

Regards


        Uz


-- 
Ullrich von Bassewitz                                  uz@musoftware.de
----------------------------------------------------------------------
To unsubscribe from the list send mail to majordomo@musoftware.de with
the string "unsubscribe cc65" in the body(!) of the mail.
Received on Fri Nov 12 15:53:00 2010

This archive was generated by hypermail 2.1.8 : 2010-11-12 15:53:04 CET