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

Remove calls to golang gcWriteBarrier functions #7484

Open
astrelsky opened this issue Feb 12, 2025 · 5 comments
Open

Remove calls to golang gcWriteBarrier functions #7484

astrelsky opened this issue Feb 12, 2025 · 5 comments
Assignees
Labels
Feature: Language/Go Status: Triage Information is being gathered

Comments

@astrelsky
Copy link
Contributor

Is your feature request related to a problem? Please describe.
I'm always frustrated when I have to manually fix this myself for every go program.

Describe the solution you'd like
During golang analysis, split the memory block containing the write barrier flag to create a block containing only the flag. Initialize this memory block, apply a dword to the flag address and set the data mutability to constant. (Setting the block to constant doesn't work in this case for some reason.) Then see that the decompiler magically removes all control flow to the gcWriteBarrier functions since they are unreachable and the decompilation is much cleaner.

Describe alternatives you've considered
Continue doing this manually every time.

@dev747368
Copy link
Collaborator

Thats an interesting solution. I've got a branch working its way to release that just tries to model the gcwritebarrier calling conventions better so you don't get any more register wonkieness during calls and returns.

I'm going to try your suggestion and see how much it changes.

@astrelsky
Copy link
Contributor Author

Thats an interesting solution. I've got a branch working its way to release that just tries to model the gcwritebarrier calling conventions better so you don't get any more register wonkieness during calls and returns.

I'm going to try your suggestion and see how much it changes.

It changes perfectly. I'm pretty sure I suggested this some time ago in another issue but it got buried.

@dev747368
Copy link
Collaborator

Do you have any shortcuts for finding the writeBarrier flag location in stripped binaries?

@astrelsky
Copy link
Contributor Author

astrelsky commented Feb 12, 2025

Do you have any shortcuts for finding the writeBarrier flag location in stripped binaries?

That's a bit tough but I see 2 different approaches.

  1. Find the condition check before any of the gcWriteBarrier calls.
  2. Find the data in uninitialized memory with the most references, it will be thousands for even small go programs.

I think the flag is actually in a global go struct that gets defined by ghidra. I don't remember what it's called though because it wasn't defined in what I have open.

@dev747368
Copy link
Collaborator

I think the flag is actually in a global go struct that gets defined by ghidra. I don't remember what it's called though because it wasn't defined in what I have open.

src/runtime/mgc.go:

//go:linkname writeBarrier
var writeBarrier struct {
        enabled bool    // compiler emits a check of this before calling write barrier
        pad     [3]byte // compiler uses 32-bit load for "enabled" field
        alignme uint64  // guarantee alignment so that compiler can use a 32 or 64-bit load
}

It seems its in its own little anon struct.

I've had some success in using the patterns of references preceding a site of interest to link anon context structs with the function that accepts that context struct, and I think something similar could easily work here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Feature: Language/Go Status: Triage Information is being gathered
Projects
None yet
Development

No branches or pull requests

3 participants