Order of functions in CC65

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems. See the NESdev wiki for more information.

Moderator: Moderators

Post Reply
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Order of functions in CC65

Post by DRW »

There's one thing that I noticed in CC65: When you write functions in C, then the resulting assembly file will not put them in the order that you actually wrote them in, but in the order of possible function head declarations.

So, if your code looks like this:

Code: Select all

void B(void);
void A(void);

void A(void)
{
}

void B(void)
{
}
then B will be the first function defined in assembly:

Code: Select all

; ---------------------------------------------------------------
; void __near__ B (void)
; ---------------------------------------------------------------

.segment	"CODE"

.proc	_B: near

.segment	"CODE"

	rts

.endproc

; ---------------------------------------------------------------
; void __near__ A (void)
; ---------------------------------------------------------------

.segment	"CODE"

.proc	_A: near

.segment	"CODE"

	rts
It doesn't really make a difference in practice, but I'd like my functions to be in a definite order in memory if that's possible.

For example, if I have various functions in memory, then the ones that belong together should go after each other:
MovePlayer
MovePlayerHelperFunction
MoveOpponent

But in this case, since MovePlayer and MoveOpponent would be declared in the header file since they need to be called from another code file while MovePlayerHelperFunction is just a local function and is therefore only declared in the .c source file, the order in assembly would be this:
MovePlayer
MoveOpponent
MovePlayerHelperFunction

So, why is this even the case?
Declarations of function headers are just there to let other translation units know what the function looks like. I can write the same declaration as often as I want. It's just a reference point.
Why is the code not ordered according to the way I actually define the functions? Or is there any way to do this?
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
Joe
Posts: 650
Joined: Mon Apr 01, 2013 11:17 pm

Re: Order of functions in CC65

Post by Joe »

DRW wrote:It doesn't really make a difference in practice
If it doesn't make a difference, why are you worried about it?
User avatar
thefox
Posts: 3134
Joined: Mon Jan 03, 2005 10:36 am
Location: 🇫🇮
Contact:

Re: Order of functions in CC65

Post by thefox »

DRW wrote:Why is the code not ordered according to the way I actually define the functions?
Why would it be? The compiler is free to choose whatever ordering it wants to as long as the code is functionally correct.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Order of functions in CC65

Post by rainwarrior »

DRW wrote:Why is the code not ordered according to the way I actually define the functions? Or is there any way to do this?
C does not, and has never had a way to specify the order of generated code. (It's even allowed to reorder the execution of individual lines, as long as it doesn't change the result.)

If you want things in a particular order, you can:
1. Place every function in its own module, and specify the order in your link command line. (CC65's linker doesn't happen to reorder things.)
2. Use assembly instead.
3. Modify and rebuild CC65 to change the behaviour.

I'm curious what use you have for ordered C code.
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Order of functions in CC65

Post by koitsu »

I'm not sure how or why this would impact anything negatively (runtime-wise). You admit it doesn't make a difference, so is this more an issue of pedanticism/OCD?

The only cases I can think of that's are even slightly "worrisome" would be where function X calls/uses function Y, but the compiler decides to re-order which function is defined first (hence function X, during compile-time, might throw an error relating to "undefined function Y") -- or the same scenario but with global variables. I've never seen this happen though (because most compilers, if not all, are multi-pass).

And that problem is easily solved through proper use of prototypes. Good C programs use prototypes, and are compiled (referring to gcc here) using -Wimplicit -Wmissing-declarations -Wmissing-prototypes.
User avatar
DRW
Posts: 2225
Joined: Sat Sep 07, 2013 2:59 pm

Re: Order of functions in CC65

Post by DRW »

koitsu wrote:I'm not sure how or why this would impact anything negatively (runtime-wise). You admit it doesn't make a difference, so is this more an issue of pedanticism/OCD?
Yeah, it's more a personal preference of having everything in the correct order. It's not really a practical issue, but it would be nice if the compiled binary has the functions in the same order as the source code.
koitsu wrote:And that problem is easily solved through proper use of prototypes. Good C programs use prototypes, and are compiled (referring to gcc here) using -Wimplicit -Wmissing-declarations -Wmissing-prototypes.
Well, that's what I do which is why I got this behavior in the first place: The order in the assembly code is based on the order of the function prototypes, not on the order of the actual functions.
I know that the compiler doesn't order the functions fully arbitrarily, so I'm wondering why the prototypes are the thing that they are ordered by, instead of the way the code is actually written from top to bottom. (Reordering of specific lines probably has to do with optimization, so that's still a different issue.)
My game "City Trouble":
Gameplay video: https://youtu.be/Eee0yurkIW4
Download (ROM, manual, artworks): http://www.denny-r-walter.de/city.html
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Order of functions in CC65

Post by rainwarrior »

koitsu wrote:The only cases I can think of that's are even slightly "worrisome" would be where function X calls/uses function Y, but the compiler decides to re-order which function is defined first (hence function X, during compile-time, might throw an error relating to "undefined function Y") -- or the same scenario but with global variables. I've never seen this happen though (because most compilers, if not all, are multi-pass).
The reordering of generated code has nothing at all to do with definition order and dependencies. Dependencies do not need to be output first, they just need to be parsed first. C and C++ compilers are never multi-pass, and this is part of the language specification.


On platforms with a distinction between short and long jump instructions, there's potential optimizations that can be made by placing code within reach of a short jump of its dependencies. I don't think CC65 has any such capability, but this is one of the reasons why it's beneficial that the output order is not specified by the language. (It specifies very little about how the output is composed, really; the only thing that matters is what it does. How it does it is the compiler-writer's concern.)
User avatar
koitsu
Posts: 4201
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Order of functions in CC65

Post by koitsu »

rainwarrior wrote:The reordering of generated code has nothing at all to do with definition order and dependencies. Dependencies do not need to be output first, they just need to be parsed first. C and C++ compilers are never multi-pass, and this is part of the language specification.

On platforms with a distinction between short and long jump instructions, there's potential optimizations that can be made by placing code within reach of a short jump of its dependencies. I don't think CC65 has any such capability, but this is one of the reasons why it's beneficial that the output order is not specified by the language. (It specifies very little about how the output is composed, really; the only thing that matters is what it does. How it does it is the compiler-writer's concern.)
Thanks for the clarification and education. My example (re: definition order) was with regards to "parsing order", meaning the compiler must have and idea of what the labels and declarations are for things which later use them (hence mentioning prototypes and said gcc warning flags). I was under the impression compilers were multi-pass for this particular reason, but that obviously isn't the case (gcc is a one-pass compiler, not sure about clang/LLVM). I guess they only need to iterate over (parse) once while keeping an in-memory list of said declarations/labels.

And yes, this is all unrelated to the actual order of the resulting output. Sorry I didn't make that clear.

This thread made me wonder about cc65 doing instruction reordering (as a point of the OP being a bit pedantic), but it looks like cc65 doesn't do that.
User avatar
rainwarrior
Posts: 8732
Joined: Sun Jan 22, 2012 12:03 pm
Location: Canada
Contact:

Re: Order of functions in CC65

Post by rainwarrior »

Well, technically the compilers might be multi-pass for the purpose of warnings or other diagnostics, or optimization, but the language itself is strictly single-pass by design, so anything a compiler might do in an additional pass is not allowed to change whether your code is valid or not.

Using a second pass to eliminate the need for a forward declaration would be non-compliant C/C++. However, using a second pass to offer a helpful suggestion in a warning or error message is totally fine.

Assemblers, on the other hand, aren't complying to any kind of specification, which is why they may be very meaningfully single or multi-pass.

If you want to know why single-pass was ever seen as an advantage, think about a time when a whole program's text wouldn't fit in RAM, and you had to load its text progressively from a tape drive. ;) I think CC65's assembler is single-pass just because of its association with C (the documentation suggests it was an arbitrary choice).
Post Reply