Page 1 of 1
CC65 LD65 unused code
Posted: Wed Jul 05, 2023 7:20 am
by Andre
Hi All,
This question is for users of the CC65 c compiler. (or simply CA65 and LD65...not really a c compiler problem)
I have some C files and some assembler files.
I compile / assemble them and then link them with LD65.
I've been doing this for a long time and it all works well.
An assembler file may contain multiple functions which are exported and used elsewhere.
What I discovered is that unused assembler functions are not removed from the final output.
I tested this by creating a dummy assembler function that is not called anywhere.
When I look at the code size in the map file I can see the size change as I link with and without the additional (unused) code.
Is there any way to tell LD65 to not include unused code?
I believe that c compilers remove unused c code. I will check if CC65 does this.
I would have expected LD65 to do the same. Or maybe it can't tell at this point what is used and not.
For example I have a file called ACIA.s
It contains various functions related the ACIA.
I use it in multiple programs, but not every program uses all the functions.
Do I split the it, one function per file and only link those functions used?
Any suggestions?
Thanks
Andre
Re: CC65 LD65 unused code
Posted: Wed Jul 05, 2023 10:05 am
by Proxy
Assemblers (and by extension assembler/linker combos) never get rid of uncalled functions, since they cannot know if the function is truly unused.
You might have some complicated calling system that constructs the address of a function and jumps to it via a table in RAM or an RTS instruction. Or have some other external code call those function.
In either case the assembler cannot know these things, and I think it's better that it doesn't assume things about the code.
One way to get rid of functions would be to use conditional blocks.
This will only assemble the contents of the block if __symbol is not 0 (or undefined). Its still manual as you have to tell it which block to include or not, so it's only slightly better than mass commenting parts of your code.
Another much better option is (like you mentioned) to simply do the same thing cc65 libraries do and place each function in it's own file, assemble them to object files, and the combine them all into a library file with AR65.
Now when you assemble and link a program you can include that library file and the linker will only use the code from files that were imported by the program.
Re: CC65 LD65 unused code
Posted: Wed Jul 05, 2023 11:48 am
by drogon
It works just like most C compilers, archives and linkers that you might use on your Linux desktop - e.g. GNU CC and so on.
Each file is a "module". And when linking the contents of that module will be included.
So..
You split the files up into procedures and start and end each one with .proc and .endproc. This is instead of label:
A side-effect is that it allows you to use the name label: names inside different PROCs in the same file.
But typically you might have each function in a separate file.
You then need to .include header files with .global directives for each .proc
You assemble each file separately. To yield a lot of .o files.
Then you 'archive' the .o files into a .a library using the ar65 command.
You can then link that in with your main program and the linker will only pull the functions (whole files) that the main program requires. (Hence putting each function in it's own file)
It might take you time to get this setup and working, but once it is, then you can have a fairly generic Makefile for each project with separate Makefile(s) to build up your librarys.
Do study the options of ar65 and ld65 to make sure you understand it all.
Personally I think it's overkill for a little hobby CPU project, but on the other hand it's also quite rewarding to think you can use the same tools and ideals in your little hobby CPU project that we use daily on our "real" work stuff.
And of-course another option is to create a run-time/shared library that's in the ROM - then you need to create a set of fixed address entry points for everything like printing a character, reading a character and so on. This is the approach I adopted in my Ruby system - which is not a million miles from the way Acorn did it in the BBC Micro and to a lesser degree Apple did it in the Apple II monitor.
"Hooks" are provided to divert various functions - e.g. in Ruby I have multiple output device capability so I can switch the output device (for printing characters) without an application knowing it's been switched - so I could have multiple UARTs or stream text to disk or an LCD, etc.
My '816 BCPL OS has an even larger shared library which is loaded into RAM at boot time and programs link into this when they get loaded from the filing system.
-Gordon
Re: CC65 LD65 unused code
Posted: Wed Jul 05, 2023 5:25 pm
by BigDumbDinosaur
One way to get rid of functions would be to use conditional blocks.
This will only assemble the contents of the block if __symbol is not 0 (or undefined). Its still manual as you have to tell it which block to include or not, so it's only slightly better than mass commenting parts of your code.
In the Kowalski assembler, I use “automatic” conditional assembly so only the functions of a library that actually get called get assembled:
Code: Select all
.if .ref(some_func) ;if a reference is made to some_func...
...assemble the some_func code...
.endif
If earlier in the program, a JSR some_func instruction was encountered, the conditional assembly requirement will be satisfied and some_func will be assembled.
The only limitation with this procedure is the reference to the function that is subject to conditional assembly must be made before the conditional assembly code is reached to avoid a forward reference error.
Re: CC65 LD65 unused code
Posted: Sun Jul 23, 2023 3:55 am
by Andre
Thanks for the input,
I have started breaking up my assembler files into one function per file and creating libraries.
Regards
Andre
Re: CC65 LD65 unused code
Posted: Mon Jul 24, 2023 10:30 am
by fachat
The xa65 assembler provides a
#iflused
Preprocessor function to assemble some code (label)only if it is actually referenced