compiler killer!??
John Ballance (21) 85 posts |
this single line c program: when compiled with the following command (in a task obey) (the switches used are all needed!, except -S and -list): dir <Obey$Dir> blows the compiler with a resource failure error and corrupt register 10 Can people reproduce this.. Can anyone suggest a way to write the same code to compile with the command line? Thanks John |
John Ballance (21) 85 posts |
n.b. the 1 (if you see it) was [ followed by 1 followed by ] |
Rick Murray (539) 13840 posts |
Minor nitpick – you have Compilation proceeds, there are two warnings (stuff not declared in a header), then it fails with you returning a value from a void function. You probably want something like this:
Ooooh boy. Yes. That’s fun. I like that. *cc -S -list -zM -zps1 -c -depend !Depend -throwback -ff -fah -c++ -ff -APCS 3/32bit/nofp/noswst -o o.bigbang c.bigbang "c.bigbang", line 2: Warning: extern 'disp_dev_lst' not declared in header "c.bigbang", line 5: Warning: extern 'get_panel_by_id' not declared in header "c.bigbang", line 7: Fatal internal error: corrupted register 10 (used but not set) Internal inconsistency: either resource shortage or compiler fault. If you cannot alter your program to avoid this failure, please contact your supplier * At a quick glance – shouldn’t the first struct be a typedef? |
Rick Murray (539) 13840 posts |
Okay.
We are describing dummy to be a struct containing a single long integer. Why isn’t this working? If I remove the array stuff (anything in square brackets), it still blows up. I’m going to dig up an ancient version of TurboC and see if that will compile it. BTW: cc v5.70 running on RPCEmu v0.8.9 with RISC OS 5.19 (14 March 2013). |
Rick Murray (539) 13840 posts |
Nope. Worked fine on TurboC++ v1.0 (ugh, the DOS shell was using American keyboard layout…). Just whinged that I needed a main() function in order to run it. I added a dummy one and a bunch of printf()s and it worked just as expected. Sorry. I think you’ve run in to a real live compiler quirk. I say “quirk”, not “bug”, because it appears that the faulty part here is the combination of
So the question I would ask is: are Remove |
Rick Murray (539) 13840 posts |
PS: Before I hit the sack – compile with “-fah” and not “-ffah”. Embedding function names doesn’t take much space, and it can aid in debugging to have names you can look for in memory. Do you need the “-c++” option? Is the code plain C or C++? Likewise, “-zps1” – wouldn’t this be better pragma’d around functions that you absolutely know for sure don’t require the safety net, instead of globally applied to entire files? |
John Ballance (21) 85 posts |
Rick, thanks for the sanity check. the -c++ is irrelevant to the issue.. fails either way. It did start with a typedef, but I kept reducing stuff till I got the minimum. Actually it is part of a large code set I’m working on.. works fine in other places. the -zM and (I believe) noswst are standard switches in rom build hal stuff. I’m hoping to ‘gain Ben’s interest’ on this.. (holidays are lovely, save when you think you’ll get good time on things, then hit this sort of thing on day 1!!) |
John Ballance (21) 85 posts |
OK.. it is down to returning a pointer to a static defined at a higher level to the routine doing the returning. -zM is module code.. and with the /noswst switch set. removing the /noswst switch enables compilation. I wonder what the long term significance of that is? |
Rick Murray (539) 13840 posts |
noswst is (you can’t have stack checking enabled for an abort handler, it would loop forever); however it does not appear to be generating module code… most of the HAL works lower than that, so the output is a plain AOF or a binary, and the C parts are generated as a regular module. It is possible that some convoluted process might have C code compiled with -zM and noswst; but without looking line by line through a log of the build, I’m not sure which parts would. Certainly, the HAL itself (that this MakeFile specifically applies to) does not appear to contain any C code at all.
[source] Everything else (BCMVideo, etc) appears to be built using the main build system, probably something like “CModule” in here, but I took a look at that MakeFile and decided the best response was to scream and run away! |
Rick Murray (539) 13840 posts |
In my build log of building a Pi ROM, I found noswst was used in two places. The second place was the assembler code for the HAL. Not the compiler.
No other occurrences of “noswst” stand out. I can send you the build log if you like, it’s a mere 877K. ;-) In short – I don’t think we have |
John Ballance (21) 85 posts |
fair enough. I’ll eliminate the noswst and see how it goes.. will need to hard check the resultant assembler though!! However, this is a compiler bug, as in no way should the compiler fail like this.. what is happening is a function is returning a pointer to a static defined outside that function, with both -zM and /noswst defined. remove the noswst and it does appear to compile thanks Rick, and a Happy New Year to you and all the rest of the crew! |
Ben Avison (25) 445 posts |
OK, this is fairly advanced compiler usage. It’s actually telling you exactly what the problem is in the error message, but you need to understand what’s going on behind the scenes to make sense of it. The important bit is the “register 10 used but not set” bit; this is referring to register R10, or to give it its APCS name, sl (for “stack limit”). The “not set” part of the error message comes from the fact that you’ve specified a noswst APCS variant – that means that code compiled that way cannot assume anything about the contents of R10 on entry, but that it can use it however it likes, so long as its initial value is restored on exit from the function. The code also obviously cannot perform any stack limit checking, so there’s at least a theoretical risk of stack overflow – but it’s an inherent limitation of APCS/noswst that you’re assumed to have taken care of it by static analysis instead. The question of why R10 is being used is answered by the -zM switch. Without this, at link time, a single copy of the static data is created just after the executable code. This is obviously no good for ROM modules, where the static data has to be in RAM – nowhere near the ROM – and its location may change at runtime (typically due to module reinitialisation). Furthermore, both ROM and soft-loaded modules may be multiply instantiated, so the address of the relevant data is at different addresses for different instantiations; obviously the absolute address of the data cannot therefore be encoded in the read-only code area of the module. Instead, the compiler makes use of relocation offsets stored in the stack chunk header, and adds these to addresses which are stored in the code area at runtime to derive the actual address of the read-write static data. But to locate the stack chunk header, the compiler needs to use the stack limit register – which hasn’t been initialised by the function’s entry conditions. Hence the error. (In theory, you could have initialised R10 using the inline assembler to avoid the error, but I won’t go into that further here.) So the short answer is that the combination of APCS/noswst, -zM and read-write data areas are mutually incompatible. In other words, if your code is or may be destined for a ROM, or a soft-loadable module that can be reinitialised or reinstantiated, then APCS/noswst code can’t use the C languages’s static data syntax; this is why some HALs define their workspace as a struct and access it using __global_reg(6) void *sb. (This does however mean you are left with the problem of having to keep the assembler and C definitions of the space in sync with one another. One simple approach is to block-allocate (say) the first 1K to assembler usage and make the C struct start with char unused[1024]; then place the C allocations afterwards.) One exception is with const static data. The compiler is bright enough to realise that if static data is declared as const, then it will be the same in each instantiation of a module, and doesn’t need reasserting when you reinitialise the module, so it saves time and memory by allocating the data in a read-only data area and omitting the relocation code. There is a gotcha there that this only happens if the data is of file scope (i.e. you need to declare it using the static keyword as well as const) – I forget the reason for that, but it might just have been for compatibility’s sake, since it was a later addition to the compiler, and people would have expected existing precompiled libraries to still work. (For completeness, I should add that const compound literals are also allocated to a read-only data area, so can also be used with APCS/noswst.) So, ironically, the compiler error is actually quite useful to stop you accidentally doing something that will cause data aborts at runtime. You need to use one of the two alternatives above. |
John Ballance (21) 85 posts |
Thank you Ben for this solid explanation, which does make sense. What I’ve missed then is that for things to work I need to declare the array as const static.. in my use that is what it is, but the place it came from obviously assumed that it was both const and static from its placement in the code. Very many thanks |