Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PowerPC comparisons returned or stored in variables decompile poorly #2801

Closed
Pokechu22 opened this issue Feb 28, 2021 · 1 comment
Closed
Labels
Milestone

Comments

@Pokechu22
Copy link
Contributor

Describe the bug
PowerPC comparisons returned or stored in variables decompile poorly, as they use countLeadingZeros(v) >> 5 as a way to check if v is 0 (as if so, v has 32 bits set to 0, and 32 >> 5 == 1).

To Reproduce
Decompile the attached binaries, using PowerPC:BE:32:default:default as the language. For instance, equals3_32 in cntlz_O1.o looks like this:

uint equals3_32(uint param_1)

{
  uint uVar1;
  
  uVar1 = countLeadingZeros(param_1 ^ 3);
  return uVar1 >> 5;
}

The 64-bit version looks sillier, producing this (note that I had to manually set the data type and set custom storage to r3 and r4 for this; by default ghidra detects it as 2 uint parameters and with just longlong it tries to place it on the stack):

uint equals3_64(longlong param_1)

{
  uint uVar1;
  
  uVar1 = countLeadingZeros((uint)((ulonglong)param_1 >> 0x20) | (uint)param_1 ^ 3);
  return uVar1 >> 5;
}

The unoptimized versions have various sign-extensions and masks that don't show up when optimisations are turned on:

uint equals3_8(char param_1)

{
  uint uVar1;
  
  uVar1 = countLeadingZeros((int)param_1 ^ 3);
  return uVar1 >> 5 & 0xff;
}

Expected behavior
The decompiled code should look closer to the original code, ideally generating param_1 == 3 in all cases (but something like param_1 ^ 3 == 0 would still be a major improvement).

Attachments
cntlz.zip — contains .o files at -O0 through -O3 with and without -g (though -O1, -O2, and -O3 are all the same without -g) compiled using powerpc-eabi-gcc provided via devkitPPC. (I release this code under CC0.)

#include <stdbool.h>
#include <stdint.h>

bool equals3_8 (int8_t  param) { return param == 3; }
bool equals3_16(int16_t param) { return param == 3; }
bool equals3_32(int32_t param) { return param == 3; }
bool equals3_64(int64_t param) { return param == 3; }

Environment (please complete the following information):

  • OS: Windows 10, insider build 19042
  • Java Version: 11.0.3
  • Ghidra Version: 9.2.2
  • Ghidra Origin: official ghidra-sre.org distro

Additional context
I have also seen variable - 3 instead of variable ^ 3, but this doesn't seem to happen with GCC.

This relates to #2121 (though I don't think adding a PcodeOp for countLeadingZeros would fix it on its own, nor am I sure that a fix would actually require adding a PcodeOp).

@ryanmkurtz
Copy link
Collaborator

Fixed by 9cf60fa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants