3

This question is about cc65, which is a toolkit including a C compiler, assembler, linker, etc. All targeting various 6502 computers, like the various 8 bit commodores, the Apple II and whatever else. In particular, I am using the cl65 command-line tool, which is a frontend to the compiler, to target the Commodore 64.

The thing is that this compiler depends very heavily on a library of little functions, that do simple things like push a 16-bit value onto a software stack (not the CPU stack!) or multiply two 16 bit values together. I am trying to get my program into a single, independent assembly, which does not rely on external subroutines.

Here is the contents of hello.c:

#include <stdio.h>
int main(void) {
    printf("Hello, World!\n");
}

Here is how I compile it:

cl65 -l hello.asm hello.c 

Here is the contents of hello.asm.

ca65 V2.13.9 - (C) Copyright 1998-2011 Ullrich von Bassewitz
Main file   : hello.s
Current file: hello.s

000000r 1               ;
000000r 1               ; File generated by cc65 v 2.13.9
000000r 1               ;
000000r 1                   .fopt       compiler,"cc65 v 2.13.9"
000000r 1                   .setcpu     "6502"
000000r 1                   .smart      on
000000r 1                   .autoimport on
000000r 1                   .case       on
000000r 1                   .debuginfo  off
000000r 1                   .importzp   sp, sreg, regsave, regbank
000000r 1                   .importzp   tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
000000r 1                   .macpack    longbranch
000000r 1                   .forceimport    __STARTUP__
000000r 1                   .import     _printf
000000r 1                   .export     _main
000000r 1               
000000r 1               .segment    "RODATA"
000000r 1               
000000r 1               L0003:
000000r 1  C8 45 4C 4C      .byte   $C8,$45,$4C,$4C,$4F,$2C,$20,$D7,$4F,$52,$4C,$44,$21,$0D,$00
000004r 1  4F 2C 20 D7  
000008r 1  4F 52 4C 44  
00000Fr 1               
00000Fr 1               ; ---------------------------------------------------------------
00000Fr 1               ; int __near__ main (void)
00000Fr 1               ; ---------------------------------------------------------------
00000Fr 1               
00000Fr 1               .segment    "CODE"
000000r 1               
000000r 1               .proc   _main: near
000000r 1               
000000r 1               .segment    "CODE"
000000r 1               
000000r 1  A9 rr            lda     #<(L0003)
000002r 1  A2 rr            ldx     #>(L0003)
000004r 1  20 rr rr         jsr     pushax
000007r 1  A0 02            ldy     #$02
000009r 1  20 rr rr         jsr     _printf
00000Cr 1  60               rts
00000Dr 1               
00000Dr 1               .endproc
00000Dr 1               
00000Dr 1               

You can see that this file includes references to things like pushax and _printf. This is only a simple example. tosmulax and many others don't appear in this one. I was hoping to have these subroutines either inlined, or appended to the source, so that I end up with a file that can be independently assembled.

Is there a way to achieve this?

3
  • V2.13.9 is obsolete, please update to V2.18.
    – Polluks
    Commented Apr 6, 2020 at 13:35
  • Good shout @Polluks! Does it change the answer any? Commented Apr 6, 2020 at 19:27
  • No but you would miss more than 300 fixed issues.
    – Polluks
    Commented Apr 7, 2020 at 7:55

3 Answers 3

1

There is no simple way, as they are separate compiled (assembly) sources. There is no common code generation stage that could easy produce a joined source. CL65 only acts as a unified command line interface.

CC65's build process doesn't take any shortcut during code generation, compilation and linking but really handles everything as it should. Code generation is done just for the sources provided and object binaries are handled as well separate. Only the linker will join them later.

You'll need to include them einter manually from their source files from the runtime library, like

or from the commons library, which is essentially the CLIB of CC65:

and so on.

Or write some script picking either function from their source file(s) and merge them. This may be for most parts straight foreward, but (like always in a C environemnt) quite tricky when it comes to import/export - as for one, some do as well use other routines and second all import/export clauses need to be normalized for the new representation.


P.S.: The same issues will arise with any other (standard) C environment, as the C-LIB which for example contains all entry and exit code, or functions like print is as well a separate compiled unit.

0

Use --mapfile to create a map file and collect all sources. Not very useful IMHO.

  1. you spread the source code and/or
  2. you spread the binary code but
  3. I have never seen included runtime sources, why? Just install the compiler!
0

As others have said, there is no easy way.

The proper solution is to not use cl65, since it's workflow is pre-defined and I do not believe very extensible.

The basic workflow for cc65 is cc65 runs to compile C source code in to as65 compatible assembly code. as65 is run to convert the assembly code in to object code. Finally, ld65, the linker, is called to linked the disparate object files together (those generated by your C code and the library code provided by the system).

In your workflow you would introduce a post processor between the cc65 step and the as64 step. This post-processor would do the things that you suggest, such as inline pushax, or append the assorted library files to the source code.

You could do this with a simple script, or even with a Makefile.

Depending on your needs, writing such a processor would not necessarily be difficult. You could probably just iterate over the lines of code, directly replace lines like jsr pushax, and just count references to external routines that would need to be included.

However, one caveat to concern yourself with is that you may have to made several passes over the code. For example, some of the library code may well make calls to other library functions not directly referenced in your code, but would still need to be included. Or, those functions might reference things you want to inline, like the pushax.

So, you can see you may need to post process the library files as well. But this is simple. You can simply run over the main file, include and inline anything you find, write a new file, and then do it all over again until nothing changes.

You may have an issue with duplicate symbols, since each file has their own namespace, if two files use the same internal label, they may conflict when combined. This type of thing bumps the potential difficulty up a notch as you would then need to rewrite the symbols. But, at the same time, as65 has some pretty robust scoping capabilities, so those may work for you as well (I'm no as65 expert, I've just skimmed the docs in the past).

You can use any modern scripting language for this. I bet you could roll this out (barring some fundamental blocker) in a short afternoon of hackery.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .