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

Decompiler: Simplify comparisons between INT_OR and zero. #6578

Conversation

LukeSerne
Copy link
Contributor

At optimisation level -O1, gcc combines several values that all need to be compared against zero by combining them using INT_OR and only comparing the combined result against zero. With this rule, the decompiler is able to break these INT_OR chains apart and simplify the individual links.

Example

As an example, let's compile the below source code with gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0 (or follow along on godbolt). Make sure to pass -O1.

#include <stdio.h>

int a = 0;
int b = 0;

int main() {
    if ((a == 0) && (b == 0)) {
        printf("zero!\n");
    }
    return 0;
}

If using godbolt, you can notice that an or instruction is used and only one jump instruction. If you're compiling locally, you can load the resulting binary in ghidra and let auto analysis run. I tested with Github release 11.0.3. The decompiler gives the following output:

undefined8 main(void)

{
  if ((a | b) != 0) {
    return 0;
  }
  puts("zero!");
  return 0;
}

Here, you can also see the binary or operator (|) being used. Together with the != 0 condition, it's not obvious at first glance that this tests if either a or b is nonzero. Additionally, in this case a and b are variables that cannot be simplified further. The expressions being or-red together might be more complex, and this structure hinders further simplification.

We can test this PR by compiling decomp_dbg and using this xml that I generated using the "Debug function decompilation" menu item. Then, we can use the command line interface decomp_dbg to see what the decompiled code would look like with this patch:

[decomp]> restore /path/to/int_or_zero.xml                          
/path/to/int_or_zero.xml successfully loaded: Intel/AMD 64-bit x86
[decomp]> load function main
Function main: 0x00101149
[decomp]> decompile
Decompiling main
Decompilation complete
[decomp]> print C

undefined8 main(void)

{
  if (a != 0 || b != 0) {
    return 0;
  }
  puts("zero!");
  return 0;
}

At -O1, gcc combines several values that all need to be compared against zero by
combining them using `INT_OR` and only comparing the combined result against
zero. With this rule, the decompiler is able to break these `INT_OR` chains
apart and simplify the individual links.
@ryanmkurtz ryanmkurtz added Feature: Decompiler Status: Triage Information is being gathered labels May 28, 2024
@ryanmkurtz ryanmkurtz added Reason: Internal effort This will be solved internally Status: Internal This is being tracked internally by the Ghidra team and removed Status: Triage Information is being gathered labels Aug 26, 2024
@ryanmkurtz ryanmkurtz added this to the 11.2 milestone Aug 26, 2024
@ryanmkurtz ryanmkurtz removed the Reason: Internal effort This will be solved internally label Aug 26, 2024
@ryanmkurtz ryanmkurtz merged commit 2ef8341 into NationalSecurityAgency:master Aug 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature: Decompiler Status: Internal This is being tracked internally by the Ghidra team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants