• In need of help understanding cc65's linker configurations

    From Colin Leroy-Mira@21:1/5 to All on Wed Dec 21 22:04:27 2022
    Hi,

    I'm trying to run a program that requires a bit more RAM than the
    default configuration and I can't figure what I'm doing wrong.

    I'm building this way:
    cl65 -c -t apple2 -C apple2-system.cfg -o program.o program.c
    cl65 -t apple2 -C apple2-system.cfg -m program.bin.map \
    -o program.bin program.o

    I can see in `appledump` that the header differs and '20 00' appears in
    place of '08 03' which means that this configuration seems to change
    something.
    But after this, I can neither 'BRUN PROGRAM' (crashes right away) nor
    start it from a loader.system named PROGRAM.SYSTEM.

    The documentation on internet is sparse and I'd love to get a few
    pointers.

    Many thanks in advance and happy holidays
    --
    Colin Leroy-Mira

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Oliver Schmidt@21:1/5 to All on Wed Dec 21 22:46:16 2022
    Hi Colin,

    I'm trying to run a program that requires a bit more RAM than the
    default configuration and I can't figure what I'm doing wrong.

    Which is the environment you want to run the program in? DOS3.3, ProDOS,
    ...?

    cl65 -c -t apple2 -C apple2-system.cfg -o program.o program.c

    There's no point in having a linker configuration file (-C *.cfg) on a compile-only command line.

    cl65 -t apple2 -C apple2-system.cfg -m program.bin.map \
    -o program.bin program.o

    There's no point in having a target definition (-t apple2) beside a linker configuration file on a link-only command line.

    In general, there's no need for separate compile and link command lines
    when just generating a program from a single source file.

    Apart from that, I don't see that using apple2-system.cfg could help you to have more RAM available. Actually pretty much the opposite.

    I can see in `appledump` that the header differs and '20 00' appears in
    place of '08 03' which means that this configuration seems to change something.

    For sure it does. If you don't know what it does, why do you use it?

    But after this, I can neither 'BRUN PROGRAM' (crashes right away) nor
    start it from a loader.system named PROGRAM.SYSTEM.

    A program generated with apple2-system.cfg isn't supposed to be invoked in either way.

    The documentation on internet is sparse and I'd love to get a few
    pointers.

    There are diverse environments to run Apple II programs in. Therefore it is hard to provide specific guidance. The existing documentation (authored by
    me) rather presumes that you exactly know "your" environment and only
    provides hints on how to make the cc65 linker do what you want it to do.

    Regards,
    Oliver

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Colin Leroy-Mira@21:1/5 to All on Thu Dec 22 09:06:01 2022
    Hello Oliver :)

    I'm trying to run a program that requires a bit more RAM than the
    default configuration and I can't figure what I'm doing wrong.

    Which is the environment you want to run the program in? DOS3.3,
    ProDOS, ...?

    ProDOS.

    cl65 -c -t apple2 -C apple2-system.cfg -o program.o program.c

    There's no point in having a linker configuration file (-C *.cfg) on a compile-only command line.

    Thanks, I wasn't sure about that :)

    cl65 -t apple2 -C apple2-system.cfg -m program.bin.map \
    -o program.bin program.o

    There's no point in having a target definition (-t apple2) beside a
    linker configuration file on a link-only command line.

    OK.

    In general, there's no need for separate compile and link command
    lines when just generating a program from a single source file.

    I've simplified the command in the example for clarity, but in reality
    this one builds with 2 .o's, so I suppose this is needed ?

    Apart from that, I don't see that using apple2-system.cfg could help
    you to have more RAM available. Actually pretty much the opposite.

    Oh, OK. I was referring to https://www.cc65.org/doc/apple2-4.html and
    it gave me the impression that it would.

    I can see in `appledump` that the header differs and '20 00'
    appears in place of '08 03' which means that this configuration
    seems to change something.

    For sure it does. If you don't know what it does, why do you use it?

    I'm trying to learn :)

    A program generated with apple2-system.cfg isn't supposed to be
    invoked in either way.

    There are diverse environments to run Apple II programs in. Therefore
    it is hard to provide specific guidance. The existing documentation
    (authored by me) rather presumes that you exactly know "your"
    environment and only provides hints on how to make the cc65 linker do
    what you want it to do.

    Indeed, I don't know what I'm doing there :) I went with -system at
    first because I couldn't find -loader.cfg. It's been removed in https://github.com/cc65/cc65/commit/f6ab932b323845313d5aeb395e01a6d095b5e76a with a comment that makes me think I should be able to figure out how
    to create a .cfg that would give my program access to $800 to $BEFF...
    But anyway, -system or -loader, I really unsure of myself and I don't
    know how to verify the results of my configuration tests, so I'm a bit
    blind about whether I'm progressing in the right direction.

    For "system", I think I should do something like set
    STARTADDRESS to $2000 and __HIMEM__ to $BF00 ?
    For "loader", $800 and $BF00 ?
    Should I change __FILETYPE__ to 0xFF too ?
    And after this, how should I invoke it, would it be by naming it "PROGRAM.SYSTEM" or should it be named "PROGRAM" of type "SYS" and have
    a companion loader.system with it?

    I'm aware it is a lot of questions at once, I hope I'm not asking too
    much :) I'd love to understand better what I'm doing instead of just
    crossing fingers my program and data will fit!

    Thanks a lot,
    --
    Colin Leroy-Mira

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Oliver Schmidt@21:1/5 to All on Thu Dec 22 09:47:49 2022
    Hi Colin,

    [environment?]

    ProDOS.

    Great :-)

    I've simplified the command in the example for clarity, but in reality
    this one builds with 2 .o's, so I suppose this is needed ?

    Nope. You can generate a program from several source files with a single
    cl65 call just fine.

    I'm aware it is a lot of questions at once, I hope I'm not asking too
    much :) I'd love to understand better what I'm doing instead of just
    crossing fingers my program and data will fit!

    Seems like (as I guessed) you need to know more about ProDOS - and the cc65
    doc is no ProDOS tutorial ;-)

    For your convenience:

    ProDOS knows the two relevant file types SYS and BIN.

    SYS files are always loaded at $2000 and memory ends at $BF00.

    BIN files are loaded anywhere above $800 and memory ends at $9600.

    So if you want $800 - $BF00, you need some kind of "trick".

    cc65 comes with my take of such a trick in a shrink-wrapped way - loader.system.

    I just reread
    https://cc65.github.io/doc/apple2.html#ss5.1 and must admit that I can't
    see what's missing in that section :-(

    Maybe in more detail and with more background...

    As you can see from my statements above about SYS and BIN, there's no magic bullet. You need to start with a SYS file so that the memory up to $BF00 is yours.

    Then you have two options:

    1. Put data that you don't need to load from disk at $800 - $2000. This is described in https://cc65.github.io/doc/apple2.html#ss5.2

    2. Have your SYS file load code/data from disk at $800 - $2000. However,
    this isn't fun for the average cc65 user, so I came up with loader.system.

    The idea behind loader.system is to not split the program you want to run
    into two parts (SYS: $2000 - $BF00 plus BIN: $800 - $2000) but rather have
    a _very_ small SYS file that loads a single BIN at $800 - (nearly) $BF00).

    What is special about loader.system?

    - It relocates itself at $300 so it is out of the way.

    - It places the necessary disk I/O buffer at $BB00 - $BF00. cc65 programs
    have by default their software stack coming down from the highest available memory so a cc65 program told to have memory available up to $BF00 (and
    having a reasonably sized software stack) won't want to load anything above $BB00.

    - It deducts the path of the BIN file to load from from its own path. This allows to use loader.system as-is without building it but rather just
    renaming it.

    So what you have to do is this:

    1. Build your program with the default linker configuration file but
    overriding the upper memory limit default $9600 to $BF00.

    2. Grab loader.system, rename it to e.g. 'myprog.system' if your program is named 'myprog'.

    3. Load your program either from the ProDOS dispatcher by selecting myprog.system or by entering on the BASIC prompt
    - myprog.system

    4. Enjoy ;-)

    Note: loader.system is no AppleSingle file, but a plain binary file. You maybe/likely need different options to put it on a disk image than you use
    for the AppleSingle files as default generated by the linker.

    Regards,
    Oliver

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Colin Leroy-Mira@21:1/5 to All on Thu Dec 22 12:06:52 2022
    Hi again Oliver,

    There's no point in having a target definition (-t apple2) beside a
    linker configuration file on a link-only command line.

    In general, there's no need for separate compile and link command
    lines when just generating a program from a single source file.

    Thanks a lot for your last reply, it makes things more clear. I'm
    coming back to this point. I'm having difficulties understanding what
    I'm doing wrong. I'm trying to make things as simple as possible, so I
    can compile my example program this way:

    cl65 -t apple2 -I../../lib normal.c ../../lib/extended_conio.c \
    -o normal.bin

    This works.

    Now, if I want to pass a linker configuration file, I'm using:
    cl65 -t apple2 -C apple2.cfg -I../../lib \
    normal.c ../../lib/extended_conio.c -o normal.bin

    I use both -t and -C because if removing -t apple2, I'm getting errors
    which makes me think it's trying to compile for c64? :

    /usr/share/cc65/include/apple2.h(41): Error: #error: This module may
    only be used when compiling for the Apple ][! /usr/share/cc65/include/apple2_filetype.h(40): Error: #error: This
    module may only be used when compiling for the Apple ][! /usr/share/cc65/include/c64.h(84): Error: Macro redefinition is not
    identical /usr/share/cc65/include/c64.h(85): Error: Macro redefinition
    is not identical [...]

    Lastly, if I pass both -t and -C, it seems -C is ignored, which seems
    kind of logical, because the resulting files are identical:

    $ cl65 -t apple2 -C apple2.cfg -I../../lib \
    normal.c ../../lib/extended_conio.c -o normal.bin

    $ cl65 -t apple2 -C loader.cfg -I../../lib \
    normal.c ../../lib/extended_conio.c -o himem.bin

    $ sha1sum *.bin
    40325c9c9d481cf5510f7bcf07e2612dd03d5fa4 himem.bin
    40325c9c9d481cf5510f7bcf07e2612dd03d5fa4 normal.bin

    (The differences between apple2.cfg and loader.cfg are:
    - __HIMEM__: type = weak, value = $9600; # Presumed RAM end
    + __HIMEM__: type = weak, value = $BF00; # Presumed RAM end

    Thanks!
    --
    Colin Leroy-Mira

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Oliver Schmidt@21:1/5 to All on Thu Dec 22 14:37:00 2022
    Hi Colin,


    Hi again Oliver,

    There's no point in having a target definition (-t apple2) beside a
    linker configuration file on a link-only command line.

    In general, there's no need for separate compile and link command
    lines when just generating a program from a single source file.

    [...]

    I use both -t and -C because if removing -t apple2, I'm getting errors
    which makes me think it's trying to compile for c64? :

    Please note that I was talking about compile-only and linky-only
    command lines. For compile-and-link command lines, it makes of course
    sense to have both -t ... and -C ...

    For the cc65 compiler, -t ... does all sorts of things you certainly
    want to have.

    For the ld65 linker, -t xyz is just a shorthand to -C xyz.cfg so it
    doesn't like to be given both.

    The cl65 tool is clever enough to pass the -t ... only to the linker
    if there's no -C ... given.

    (The differences between apple2.cfg and loader.cfg are:
    - __HIMEM__: type = weak, value = $9600; # Presumed RAM end
    + __HIMEM__: type = weak, value = $BF00; # Presumed RAM end

    cc65 linker configurations aren't 100% stable. So you are strongly
    advised to _not_ copy one, just edit a value or two and use the copy.
    This tends to make your build break in ways you don't understand with
    later cc65 versions. You're far better off with setting __HIMEM__ from
    the command line as shown in the documentation.

    Note: If you use, cl65 you need to use -Wl (aka --ld-args) to set
    __HIMEM__ from the command line - see
    https://cc65.github.io/doc/cl65.html#s2.

    Regards,
    Oliver

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Colin Leroy-Mira@21:1/5 to All on Thu Dec 22 17:31:41 2022
    Hi,

    [snip]
    cc65 linker configurations aren't 100% stable. So you are strongly
    advised to _not_ copy one, just edit a value or two and use the copy.
    This tends to make your build break in ways you don't understand with
    later cc65 versions. You're far better off with setting __HIMEM__ from
    the command line as shown in the documentation.

    Thanks a lot for all the details, Oliver, that helps a lot, and is
    appreciated!

    --
    Colin Leroy-Mira

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Oliver Schmidt@21:1/5 to All on Thu Dec 22 18:47:20 2022
    Hi Colin,

    Thanks a lot for all the details, Oliver, that helps a lot, and is >appreciated!

    You're welcome! Thanks for the kind feedback :-)

    Regards,
    Oliver

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Colin Leroy-Mira@21:1/5 to All on Fri Dec 23 23:50:31 2022
    Hi!

    cc65 linker configurations aren't 100% stable. So you are strongly
    advised to _not_ copy one, just edit a value or two and use the copy.
    This tends to make your build break in ways you don't understand with
    later cc65 versions. You're far better off with setting __HIMEM__ from
    the command line as shown in the documentation.

    I've done some more tests, and am still under the impression that
    binaries produced with -Wl -D__HIMEM__=0xBF00 and -Wl
    -D__HIMEM__=0x9600 are exactly the same.

    But I've also noticed, using this test file, that the available memory
    is somehow automatically made known by the loader.system mechanisme ?

    https://github.com/colinleroy/aoc2022/blob/master/a2tools/src/ramtest/ramtest.c

    When ran using `BRUN RAMTEST`, _heapmemavail() tells me about 28kB,
    whereas when using `- RAMTEST.SYSTEM`, it tells me about 38kB.

    The malloc()/memset() loop then allocates and clears what is expected
    without crash.

    Do I have the correct impression?

    PS - on the other hand, -Wl -D,__STACKSIZE__= produces a different
    binary and is clearly taken into account.

    Thanks!
    --
    Colin Leroy-Mira

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jerry Penner@21:1/5 to Colin Leroy-Mira on Sun Dec 25 02:02:06 2022
    Colin Leroy-Mira <colin@colino.net> writes:

    Hi!

    cc65 linker configurations aren't 100% stable. So you are strongly
    advised to _not_ copy one, just edit a value or two and use the copy.
    This tends to make your build break in ways you don't understand with
    later cc65 versions. You're far better off with setting __HIMEM__ from
    the command line as shown in the documentation.

    I've done some more tests, and am still under the impression that
    binaries produced with -Wl -D__HIMEM__=0xBF00 and -Wl
    -D__HIMEM__=0x9600 are exactly the same.

    But I've also noticed, using this test file, that the available memory
    is somehow automatically made known by the loader.system mechanisme ?

    https://github.com/colinleroy/aoc2022/blob/master/a2tools/src/ramtest/ramtest.c

    When ran using `BRUN RAMTEST`, _heapmemavail() tells me about 28kB,
    whereas when using `- RAMTEST.SYSTEM`, it tells me about 38kB.

    When you BRUN a program, you've got BASIC.SYSTEM loaded and thus its
    memory is marked as allocated by ProDOS; everything from $9600 and up.
    When you run a system program, i.e. `- RAMTEST.SYSTEM`, BASIC.SYSTEM has
    been discarded, and you have the memory from just after your system
    program up to $BEFF available. ProDOS reserves the $BF00-$BFFF page for
    its global page.

    The malloc()/memset() loop then allocates and clears what is expected
    without crash.

    Do I have the correct impression?

    PS - on the other hand, -Wl -D,__STACKSIZE__= produces a different
    binary and is clearly taken into account.

    Thanks!

    --
    --
    Jerry jerry+a2 at jpen.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Colin Leroy-Mira@21:1/5 to All on Sun Dec 25 14:06:42 2022
    Hi,

    When you BRUN a program, you've got BASIC.SYSTEM loaded and thus its
    memory is marked as allocated by ProDOS; everything from $9600 and up.
    When you run a system program, i.e. `- RAMTEST.SYSTEM`, BASIC.SYSTEM
    has been discarded, and you have the memory from just after your
    system program up to $BEFF available. ProDOS reserves the
    $BF00-$BFFF page for its global page.

    OK, thanks for the confirmation :)

    Have a nice holiday,
    --
    Colin Leroy-Mira

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Oliver Schmidt@21:1/5 to All on Mon Dec 26 00:55:58 2022
    Hi Colin,

    I've done some more tests, and am still under the impression that
    binaries produced with -Wl -D__HIMEM__=0xBF00 and -Wl
    -D__HIMEM__=0x9600 are exactly the same.

    But I've also noticed, using this test file, that the available memory
    is somehow automatically made known by the loader.system mechanisme ?

    Your impression is correct. The __HIMEM__ setting is a pure hint telling
    the linker what value to assume. This approach allows the linker to
    estimate if things are are going to work at runtime.

    The actual HIMEM value is always determined at load time. The linker
    doesn't even try to relate the link time value to the load time. Therefore
    the link time value is in no way represented in the binary.

    When ran using `BRUN RAMTEST`, _heapmemavail() tells me about 28kB,
    whereas when using `- RAMTEST.SYSTEM`, it tells me about 38kB.

    The malloc()/memset() loop then allocates and clears what is expected
    without crash.

    Do I have the correct impression?

    Yes, this is a feature. If your program is small enough to load both
    directly and via loader.system, then you can chose if you want to directly return with less heap memory or quit to the ProDOS dispatcher with more
    heap memory.

    PS - on the other hand, -Wl -D,__STACKSIZE__= produces a different
    binary and is clearly taken into account.

    Yes, the logic goes like this:

    'Heap End' = 'Runtime HIMEM' - __STACKSIZE__

    Regards,
    Oliver

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Colin Leroy-Mira@21:1/5 to All on Wed Dec 28 21:54:31 2022
    Hi,

    Yes, this is a feature. If your program is small enough to load both
    directly and via loader.system, then you can chose if you want to
    directly return with less heap memory or quit to the ProDOS
    dispatcher with more heap memory.

    Thanks Oliver, everything makes sense!

    --
    Colin Leroy-Mira

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)