d0k3 / GodMode9

GodMode9 Explorer - A full access file browser for the Nintendo 3DS console :godmode:
GNU General Public License v3.0
2.07k stars 192 forks source link

GodMode9 compiled with gcc 14.1.0 hangs at boot #859

Closed profi200 closed 2 weeks ago

profi200 commented 1 month ago

As discussed on the server here is the issue.

How to reproduce: Compile GodMode9 with devkitARM r64 (gcc 14.1.0) and try to boot it from Luma3DS or fastboot3DS. It will hang on blackscreens (no backlight). Have not tried to compile under Windows so can't say for sure if the behavior differs but i doubt it. It's likely undefined behavior somewhere that gets detected and optimized in a way that breaks the code.

Probably unrelated to the actual issue this new warning popped up:

lto-wrapper: warning: using serial compilation of 8 LTRANS jobs
lto-wrapper: note: see the '-flto' option documentation for more information
/opt/devkitpro/devkitARM/bin/../lib/gcc/arm-none-eabi/14.1.0/../../../../arm-none-eabi/bin/ld: warning: arm9.elf has a LOAD segment with RWX permissions
urherenow commented 1 month ago

in the last few (I think) versions of dkp toolsets, that warning pops up for most large Switch projects as well. It doesn't seeem to be an issue with any of them, though.

astronautlevel2 commented 3 weeks ago

+1 to this being optimization related - compiling at the -O1 level rather than -Os lets it behave as expected, so there's probably some optimization in the O2 set that breaks it.

astronautlevel2 commented 3 weeks ago

After further investigation, it seems to be the ipa-vrp (interprocedural propagation of value ranges) optimization that breaks things - compiling with -fno-ipa-vrp results in a binary that works fine.

DarkRTA commented 3 weeks ago

opt flags breaking code reeks of UB

profi200 commented 3 weeks ago

If no one has time i guess i will try and narrow down the buggy code later. But it's annoying that i don't even have output to the LCD. I will have to see what else i can use.

profi200 commented 3 weeks ago

Found the bug. When compiling with LTO size 0 is passed to mmuMapArea() here because the rodata section size is 0: https://github.com/d0k3/GodMode9/blob/dab90a916220ac9613cdf7c299053dbf0917ab2f/arm11/source/system/sys.c#L84

The decompilation shows the loop has been optimized to a do {} while() loop:

int __fastcall mmuMapArea(u32 va, u32 pa, u32 size, u32 flags)
{
  u32 v8; // r12
  int v9; // r3
  int v10; // r10
  int result; // r0

  do
  {
    v8 = va | pa | size;
    v9 = v8 & 0xFFFFF;
    if ( (v8 & 0xFFFFF) != 0 )
    {
      if ( (v8 & 0xFFF) != 0 )
      {
        while ( 1 )
          ;
      }
      v10 = 4096;
      v9 = 1;
    }
    else
    {
      v10 = 0x100000;
    }
    result = (*((int (__fastcall **)(u32, u32, u32))&gicDefaultIrqCfg[144].low + 2 * v9))(va, pa, flags);
    size -= v10;
    va += v10;
    pa += v10;
  }
  while ( size );
  return result;
}