It is currently Sun Oct 22, 2017 4:02 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 9 posts ] 
Author Message
PostPosted: Sat Jul 09, 2016 2:26 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1405
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:
void B(void);
void A(void);

void A(void)
{
}

void B(void)
{
}

then B will be the first function defined in assembly:
Code:
; ---------------------------------------------------------------
; 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?

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 2:38 pm 
Offline

Joined: Mon Apr 01, 2013 11:17 pm
Posts: 437
DRW wrote:
It doesn't really make a difference in practice

If it doesn't make a difference, why are you worried about it?


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 2:50 pm 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 2963
Location: Tampere, Finland
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: kkfos.aspekt.fi


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 3:57 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5732
Location: Canada
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.


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 4:05 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
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.


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 4:17 pm 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1405
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.)

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 4:32 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5732
Location: Canada
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.)


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 4:54 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
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.


Top
 Profile  
 
PostPosted: Sat Jul 09, 2016 5:02 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5732
Location: Canada
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).


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 16 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:  
Powered by phpBB® Forum Software © phpBB Group