6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 11:19 pm

All times are UTC




Post new topic Reply to topic  [ 6 posts ] 
Author Message
 Post subject: CC65 LD65 unused code
PostPosted: Wed Jul 05, 2023 7:20 am 
Offline

Joined: Mon May 03, 2021 12:07 am
Posts: 21
Location: Brisbane Australia
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


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 05, 2023 10:05 am 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
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.
Code:
.if __symbol
Assembly here
.endif

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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 05, 2023 11:48 am 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1488
Location: Scotland
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

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Wed Jul 05, 2023 5:25 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8507
Location: Midwestern USA
Proxy wrote:
One way to get rid of functions would be to use conditional blocks.
Code:
.if __symbol
Assembly here
.endif

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:
          .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.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Sun Jul 23, 2023 3:55 am 
Offline

Joined: Mon May 03, 2021 12:07 am
Posts: 21
Location: Brisbane Australia
Thanks for the input,

I have started breaking up my assembler files into one function per file and creating libraries.

Regards
Andre


Top
 Profile  
Reply with quote  
PostPosted: Mon Jul 24, 2023 10:30 am 
Offline

Joined: Tue Jul 05, 2005 7:08 pm
Posts: 1043
Location: near Heidelberg, Germany
The xa65 assembler provides a
#iflused
Preprocessor function to assemble some code (label)only if it is actually referenced

_________________
Author of the GeckOS multitasking operating system, the usb65 stack, designer of the Micro-PET and many more 6502 content: http://6502.org/users/andre/


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 6 posts ] 

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 12 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: