Re: [cc65] linking to o65

From: Ullrich von Bassewitz <uz1musoftware.de>
Date: 2012-01-19 18:53:56
Hi!

On Thu, Jan 19, 2012 at 05:02:15PM +0100, Gábor Lénárt wrote:
> Thanks for the answer, I guess I start with the lunix target (of ld65), as
> it seems ld65 generates o65 for that, so the situation can be somewhat
> similar.

There have been people successfully generating o65 output for Lunix using
ld65, so I do assume that it works up to some degree. If you want your own OS
id, you ask Andre Fachat for one and add it as a number in the linker config
file (specifying "os = 5" instead of "os = lunix").

> Btw, I am not really sure if it's sane what I want. If I compile a C program
> with cc65 I can see references like these in the generated asm:
>
> jsr     pushax
> jsr     incax2
> jsr     _printf
>
> I would like not only _printf() call is implemented "by my own" but also
> internal stuffs like pushax and incax2. I have the hope with this that
> loaded programs (in o65 format) can be as small as possible, since the
> described functionality is implemented by the "loader" and anyway they are
> common in all code, so why would I store them again and agin in every
> programs? Just for information: my ultimate goal is to write some "hobby OS"
> by my own (for DTV, where there is enough RAM, relocatable stack/zero page,
> etc, so a multitask OS can be implemented more easily than with a stock C64
> for example), even with multitasking. The "loader stuff" is just the first
> step to test some of my ideas, no multitask, and other similar features yet.

While I can see your point, there are facts that will make a separate
implementation difficult: The compiler knows about many of the internal
functions. It knows which registers pass values, which ones are destroyed, and
which ones have known values on exit. In the examples above:

    pushax
        Uses the register values passed in A/X, retains these register values,
        destroys Y, doesn't modify zeropage locations.

    incax2
        Uses the register values passed in A/X, has an output in A/X but
        doesn't touch the Y register and zero page locations.

For the compiler, this knowledge means for example: A load of the Y register
before calling pushax is useless and can be removed, because the Y register is
destroyed anyway. Or: A known value in the Y register may be reused after
incax2 was called, since it didn't change.

So your implementation would not only need to implement these functions, but
would also make the behaviour identical when it comes to register usage. Which
might change at any time, so this is an almost impossible task.

But you can use a similar approach as contiki did. Compile as many of the
runtime functions into your "loader". Use the map file to determine the
addresses of these functions. Use some perl magic to generate a file with the
addresses of the functions:

        .export pushax  := $38FE
        .export incax2  := $3925
        ...

Generate an object file from this source by feeding it to the assembler, then
link this object file to your applications. As a result, the applications will
use the copies of the runtime functions already present in your loader.
Without any overhead when loading.

The drawback of this solution is, that you will have to regenerate the address
list and recompile your applications whenever any of the addresses will
change.

> What made me a bit unsure: how "stable" the "internal ABI/API"? I mean about
> pushax, etc. Is it common to have a new function like this with a new cc65
> version? Since if I implement those by my own, I will have problem with a
> newer cc65 if it uses things differently, or new stuff is introduced etc.

It is not uncommon that new functions are added and sometimes existing ones
will change. But for the reasons outlined above, I will advise against your
own implementation anyway.

> Well, if lunix target works well, it will be ok, I can create a
> configuration similar to the lunix starting with the linker config file
> dumped with ld65 (ld65 --dump-config lunix) and modified for my needs. I guess :)

That is probably the best idea until you have some stuff running. You can ask
Andre for your own OS id later.

> > There's also a reason not to rely on imports: The string table for the names
> > of the symbols may get rather big. This is the reason why loadable drivers
> > (which a in o65 format) use a jump table instead of imports by name.
>
> That's an important point.

... and probably the reason why neither cc65 modules nor Lunix do really use
o65 imported symbols. Just have a look into a cc65 generated map file and add
up the lengths of all the external names. Lunix uses just one symbol that is
the address of a jump table over which all API functions can be reached.

> Just I had the dream that there can be an OS
> which has programs compatible with any computers which can run that OS and
> use the same CPU, but the exact type of the computer is not important.

That's a very ambitious goal. You might get further with a target that's
easier to achieve.

> I see. I would not use the .o format of cc65 directly as I guess it's not
> designed for this purpose (maybe not so easy to handle on a pre-PC era based
> system with limited resources, and also it's for internal use, as far as I
> can guess it's not even always "stable" in the sense that the format can
> change, while o65 is quite simple and has a well-defined structure by a
> documentation. If I am wrong, execuse me).

Yes. o65 is what you're looking for. It has been designed by Andre with
6502/816 operating systems in mind. It is less qualified for more complex
applications, this is why I didn't use it as an intermediate format for cc65.

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 Thu Jan 19 18:54:10 2012

This archive was generated by hypermail 2.1.8 : 2012-01-19 18:54:13 CET