Help with GCC issue

Not for the first time, changing the version of GCC I use to compile my code has broken something. The specific code is this:
esi = oldesi - 1;
esi = argue((signed char *)accs - 1, (void *)(esp + 2), 1);
where esi is declared as a global register variable thus:
register signed char *esi asm ("esi");	// Program pointer
The code always used to work, but now it doesn't; seemingly the compiler doesn't realise that esi is used inside argue(). I can fix it by inserting an artificial sequence point:
esi = oldesi - 1;
printf("");
esi = argue((signed char *)accs - 1, (void *)(esp + 2), 1);
Although this fix is effective, obviously I don't want to leave it in the code. What is the best way for me to workaround what appears to be a compiler bug?

Comments

  • I can fix it by inserting an artificial sequence point:
    esi = oldesi - 1;
    printf("");
    esi = argue((signed char *)accs - 1, (void *)(esp + 2), 1);
    
    Although this fix is effective, obviously I don't want to leave it in the code. What is the best way for me to workaround what appears to be a compiler bug?
    A simpler fix is this:
    volatile int seq;
    esi = oldesi - 1;
    for (seq=0; seq<1; seq++);
    esi = argue((signed char *)accs - 1, (void *)(esp + 2), 1);
    
    although, interestingly, replacing the for statement with seq++; doesn't work.

    Generally when I report this kind of behaviour at programming forums I get the response that my code is invoking Undefined Behaviour so I shouldn't expect it to work, but if that is the case why?
  • Generally when I report this kind of behaviour at programming forums I get the response that my code is invoking Undefined Behaviour so I shouldn't expect it to work, but if that is the case why?
    I was hoping that somebody here, with more experience and knowledge of C than I have (so that's almost anybody!), would be able to help; but seemingly not. :'(

    I can leave the crude 'fix' in the code and hope for the best, despite not understanding either the cause or why the fix works. But it's not very satisfactory, especially in published Open Source software.
  • There's a tool called cppcheck which might possibly give an explanation when it finds code which it finds troublesome.
  • BigEd wrote: »
    There's a tool called cppcheck which might possibly give an explanation when it finds code which it finds troublesome.
    I can try that, but my expectation is that it won't help because global register variables (which are of course key to the issue, I'm certain it wouldn't happen with regular global variables) are a non-standard GCC extension, indeed just about the only GCC extension not also supported by Clang,

    So I wouldn't be at all surprised if cppcheck simply says what's this global register variable thing? That's not legal C!
  • I have kept quiet, because I don't understand what the snippet is trying to do.
    You're setting ESI, then setting it again with no reference to what it was before, so ordinarily I would see the first line as completely superfluous - but I am expecting there is some hidden magic going on.
  • Another possible issue is that you'll get heaps of warnings, which you'd prefer not to be bombarded with. Many will be false positives, I think, that being the nature of such static analyses. (The other modern open source C compiler, clang, also has some static analysis competence, and again it's possible the warnings will be helpfully informative.)

    There's a good chance you're already aware of Compiler Explorer at godbolt.org which offers many versions of many compilers with many targets. It might be useful in exploring what you can do, or what diagnostics you can get, if you have a small enough test case to suit that tool. (I don't know what the capacity is.)
  • BigEd wrote: »
    if you have a small enough test case to suit that tool.
    But I don't have a small test case, I have BBC BASIC for SDL 2.0 (about 500 Kbytes of binary code)! Producing an MRE would be a necessary pre-requisite to reporting it as a compiler bug, but it would probably be difficult to do.
  • Soruk wrote: »
    You're setting ESI, then setting it again with no reference to what it was before, so ordinarily I would see the first line as completely superfluous - but I am expecting there is some hidden magic going on.
    In my initial post above I stated that "esi is used inside argue()" so there's nothing hidden or magical, the first line changes the value of esi which affects what happens inside argue(). Effectively esi is a parameter to argue(), although as is common in interpreters that's achieved by it being a global.

    The GCC docs refer to global register variables being "useful in programs such as programming language interpreters that have a couple of global variables that are accessed very often" which is exactly the case in BBC BASIC

    I haven't reproduced here my entire post to the BBC BASIC forum, but there I also stated that "This code normally runs fine (on multiple platforms and CPU types)", to which I might have added "and multiple compilers". Neither GCC nor Clang (in multiple incarnations, for example built into tools like Android Studio and Apple's Xcode) issue any warnings.

    Is there something in my code that you're concerned about, for example in possibly resulting in UB?
  • Richard_Russell
    edited October 2023
    Soruk wrote: »
    You're setting ESI, then setting it again with no reference to what it was before, so ordinarily I would see the first line as completely superfluous - but I am expecting there is some hidden magic going on.
    In my initial post above I stated that "esi is used inside argue()"
    And indeed I also stated "seemingly the compiler doesn't realise that esi is used inside argue()" so I don't see how I could have been much clearer on this point.

    As a professional C programmer you may disapprove of globals, as do I in ordinary circumstances, but as the GCC docs confirm, their use is quite normal in language interpreters. I wouldn't be at all surprised if Brandy uses globals for the same reason.

    In any case, as you know the C code in question (like all of BBCSDL) was created semi-mechanically from the assembly language code of BB4W, and in assembly language everything is a global (I know that some 'high level' assemblers do support function calls with parameters and the like, but that's different from the machine-level programming I used to do).
  • Fair enough. I completely missed that when I read your original post late at night, so half asleep I got the wrong impression. Sorry about that. My mind is also somewhat elsewhere, my big focus at the moment is doing my best to assist my son getting him ready to try for a choir school, so unsurprisingly very little has happened with Matrix Brandy (aside writing the Note Quiz, again to help with his music).
  • Soruk wrote: »
    very little has happened with Matrix Brandy...
    At least that's hopefully temporary. I'm not going to be making any more changes to my BASICs, bar bug fixes (if I'm able), it's the end of the road for me as far as major projects are concerned.

    I don't have any regrets: there are no burning ambitions for my software that I'm not going to be able to fulfil, nor anything crucial left in the 'to do' list.
Sign In or Register to comment.