Skip to content

Conversation

@luoliwoshang
Copy link
Member

Summary

  • Add PreloadLinknames to collect linknames from runtime AST before user code compilation
  • Add fnlink resolution in rtFunc to properly resolve linkname targets
  • Add platform-specific sigsetjmp files (sigsetjmp for non-linux, __sigsetjmp for linux)

Problem

When rtFunc("Sigsetjmp") was called, it generated calls to runtime.Sigsetjmp instead of the C symbol sigsetjmp. This was because:

  1. rtFunc() didn't call fnlink to resolve linkname
  2. User code compiles before runtime package, so linknames weren't collected yet

Solution

Preload runtime linknames from AST right after SetRuntime, before user code compilation.

Test plan

  • _demo/go/defer/ runs correctly with output: error, 10, 5

Fixes #1483

🤖 Generated with Claude Code

@gemini-code-assist
Copy link

Summary of Changes

Hello @luoliwoshang, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request resolves an issue where calls to rtFunc("Sigsetjmp") were incorrectly generating calls to runtime.Sigsetjmp instead of the corresponding C symbol. The core problem stemmed from rtFunc not resolving linknames and the linknames themselves not being collected early enough in the compilation process. The solution involves preloading runtime linknames from the AST before user code compilation and enhancing rtFunc to utilize this preloaded information. Additionally, platform-specific sigsetjmp definitions are introduced to ensure correct C symbol linking across different operating systems, leading to more accurate and robust runtime function calls.

Highlights

  • Preloading Runtime Linknames: Introduced a new mechanism to preload //go:linkname directives from the runtime package's Abstract Syntax Tree (AST) before user code compilation. This ensures that linkname information is available early in the build process.
  • Enhanced rtFunc Linkname Resolution: Modified the rtFunc method to properly resolve //go:linkname targets. This change allows runtime functions to correctly map to their intended C symbols, addressing a previous issue where rtFunc calls were not resolving linknames.
  • Platform-Specific sigsetjmp Definitions: Added new platform-specific files (sigsetjmp.go and sigsetjmp_linux.go) within the runtime package. These files define the Sigsetjmp function with appropriate //go:linkname directives to C.sigsetjmp or C.__sigsetjmp based on the operating system.
  • Updated Sigsetjmp Builder: The Sigsetjmp builder in ssa/eh.go was updated to leverage the new rtFunc linkname resolution, simplifying the logic for calling the correct sigsetjmp C function based on the target platform.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request correctly addresses an ordering issue with go:linkname resolution for the runtime package. The solution, which involves pre-loading linknames from the runtime's AST before compiling user code, is well-implemented. The changes effectively simplify the sigsetjmp handling by centralizing the logic and properly enabling linkname resolution in rtFunc. I have one suggestion to improve the robustness of parsing //go:linkname directives.

cl/import.go Outdated
Comment on lines 680 to 687
text := strings.TrimSpace(line[len(linkname):])
if idx := strings.IndexByte(text, ' '); idx > 0 {
name := text[:idx]
if name == inPkgName {
link := strings.TrimLeft(text[idx+1:], " ")
prog.SetLinkname(fullName, link)
}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current parsing of the //go:linkname directive using strings.IndexByte and strings.TrimLeft is a bit fragile. It could incorrectly parse directives with extra fields. For instance, //go:linkname localname linkname extrastuff would result in linkname extrastuff being treated as the link target, which is likely not the intended behavior.

Using strings.Fields would make the parsing more robust by ensuring that the directive has exactly two arguments, which aligns with how the Go toolchain handles these directives.

Suggested change
text := strings.TrimSpace(line[len(linkname):])
if idx := strings.IndexByte(text, ' '); idx > 0 {
name := text[:idx]
if name == inPkgName {
link := strings.TrimLeft(text[idx+1:], " ")
prog.SetLinkname(fullName, link)
}
}
fields := strings.Fields(line[len(linkname):])
if len(fields) == 2 {
name := fields[0]
if name == inPkgName {
link := fields[1]
prog.SetLinkname(fullName, link)
}
}

@xgopilot
Copy link

xgopilot bot commented Dec 25, 2025

Code Review Summary

This PR successfully fixes the linkname resolution issue for runtime functions. The implementation is architecturally sound and follows existing patterns. I've reviewed the changes across code quality, performance, documentation, and security dimensions.

Key Findings:

  • ✅ No critical issues or blockers
  • ⚠️ Code duplication between preloadLinknameFromDoc and initLinknameByDoc should be refactored
  • ⚠️ Remove commented-out code in ssa/eh.go
  • 📝 Documentation needs improvement for the new PreloadLinknames() function
  • 🚀 Performance impact is negligible (< 0.1% compilation time)
  • 🔒 No security vulnerabilities identified

See inline comments for specific recommendations.

@xgopilot
Copy link

xgopilot bot commented Dec 25, 2025

Detailed Review Findings

Code Quality Issues

1. Code Duplication in cl/import.go:672

Severity: Medium

The preloadLinknameFromDoc function duplicates logic from initLinknameByDoc (lines 276-289). Both functions parse //go:linkname directives from AST comments. Consider extracting common parsing logic into a shared helper function to improve maintainability.

2. Commented Code in ssa/eh.go:115-118

Severity: Minor

Remove the commented-out code showing the old implementation. The git history already documents this change, and keeping dead code reduces readability.

Documentation Issues

3. Missing Documentation for PreloadLinknames() in cl/import.go:660

Severity: Medium

This exported function needs comprehensive documentation explaining:

  • Why preloading is necessary (the problem it solves)
  • When it should be called in the compilation pipeline
  • What happens if it's not called
  • The relationship to rtFunc() resolution

4. Undocumented Runtime Functions

Severity: Low

Add function documentation to:

  • runtime/internal/runtime/sigsetjmp.go:11 - Explain the wrapper's purpose
  • runtime/internal/runtime/sigsetjmp_linux.go:11 - Explain why Linux uses __sigsetjmp

Positive Observations

Clean Architecture: Preloading happens at the right time, and platform-specific behavior uses build tags appropriately

Performance: Negligible impact (< 0.1% compilation time increase)

Security: No vulnerabilities identified; proper input handling and validation

Minimal Changes: The modification to rtFunc() maintains backward compatibility

Recommendations Summary

Before Merge:

  1. Add comprehensive documentation to PreloadLinknames()
  2. Remove commented-out code in ssa/eh.go

Future Improvements:
3. Refactor linkname parsing to reduce code duplication
4. Add function documentation to runtime sigsetjmp files

@codecov
Copy link

codecov bot commented Dec 25, 2025

Codecov Report

❌ Patch coverage is 92.85714% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.76%. Comparing base (05299c6) to head (555496d).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
ssa/package.go 78.94% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1508      +/-   ##
==========================================
- Coverage   90.93%   90.76%   -0.18%     
==========================================
  Files          44       44              
  Lines       11525    11495      -30     
==========================================
- Hits        10480    10433      -47     
- Misses        883      901      +18     
+ Partials      162      161       -1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@luoliwoshang luoliwoshang marked this pull request as draft December 25, 2025 07:01
@luoliwoshang luoliwoshang force-pushed the fix/rtfunc-linkname-1483 branch 2 times, most recently from 4290ded to 847110d Compare December 25, 2025 08:18
Extend ParsePkgSyntax to collect //go:linkname and //llgo:link directives
during package loading. This reuses the existing dedup.SetPreload mechanism
to ensure all linknames (including runtime package) are collected before
compilation begins.

Changes:
- Add function and variable linkname collection to ParsePkgSyntax
- Add collectLinknameFromDoc helper function for linkname parsing
- Use sync.Map for linkname storage to support concurrent package loading
- Keep fnlink resolution in rtFunc for linkname substitution

The ParsePkgSyntax function is already called during package loading via
dedup.SetPreload, so this change naturally integrates with the existing
build flow without requiring special handling for the runtime package.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@luoliwoshang luoliwoshang force-pushed the fix/rtfunc-linkname-1483 branch from 847110d to c078e08 Compare December 25, 2025 08:28
luoliwoshang and others added 6 commits December 25, 2025 18:03
Move linkname and export collection logic from initFiles to
ParsePkgSyntax, which runs during package loading phase.

Changes:
- Add exports sync.Map to Program for storing export declarations
- Add SetExportName, ExportName, CopyExportsTo methods to Program
- Extend collectLinknameFromDoc to handle //export directives
- Move package C auto-export logic to ParsePkgSyntax
- Simplify initFiles to only collect skip names

This consolidates all AST comment parsing in one place and allows
cPkg to be determined directly from pkg.Name() == "C".

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Alt packages (e.g. github.com/goplus/llgo/runtime/internal/lib/os)
should register linknames using the original package path (e.g. os),
not their own path. Otherwise linkname lookups fail because symbols
are stored under the wrong namespace.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
When //export directive has a different name than the function and
enableExportRename is false (non-embedded target), the compiler should
panic with "export comment has wrong name" error. This was missing in
the refactored collectLinknameFromDoc function.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Remove the initLinknameByDoc function which is no longer needed after
moving linkname/export collection to ParsePkgSyntax. The initLinkname
and initLink functions are retained as they are still used by
pkgSymInfo.initLinknames for processing decl-only packages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
After moving linkname collection to ParsePkgSyntax (which runs during
package loading), the syms.initLinknames(p) call in importPkg became
redundant. ParsePkgSyntax already processes all packages' linknames
at load time via dedup.SetPreload, so there's no need to re-process
them during compilation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
After refactoring linkname collection to ParsePkgSyntax during package
loading, the following code is no longer needed:

- pkgSymInfo type and its methods (addSym, initLinknames)
- context.initLinkname and context.initLink methods
- Related constants (noDirective, hasLinkname, unknownDirective)
- Related test functions (TestErrInitLinkname, TestHandleExportDiffName,
  TestInitLinkExportDiffNames)
- Simplified importPkg to only set pkgInfo.kind

The linkname/export collection is now handled entirely by
ParsePkgSyntax which runs during package loading via dedup.SetPreload.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@luoliwoshang luoliwoshang force-pushed the fix/rtfunc-linkname-1483 branch 6 times, most recently from 8e1c797 to b21cbaf Compare December 26, 2025 09:12
- Rename functions to match original naming convention (init* prefix)
- Move initLinknameByDoc after initFiles function
- Simplify implementation to return hasLinkname directly when directive found
- Update all tests to use new function names

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@luoliwoshang luoliwoshang force-pushed the fix/rtfunc-linkname-1483 branch from b21cbaf to 30db70d Compare December 26, 2025 09:16
luoliwoshang and others added 6 commits December 26, 2025 17:34
Add isVar parameter to the closure signature for future use in
distinguishing function and variable linknames.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Pass isVar to distinguish function linknames (false) from variable
linknames (true) when collecting linkname directives.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
- Update TestErrInitLinkname to use package-level initLinkname with nil prog
- Update TestHandleExportDiffName to use package-level initLinkname
- Update TestInitLinknameByDocExportDiffNames to use package-level initLinknameByDoc
- Update TestInitLinkExportDiffNames to properly simulate enableExportRename behavior
- Use prog.ExportName() instead of pkg.ExportFuncs() for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Minimize diff by keeping variable declarations and assignments
the same as main branch, only removing the goto and linkname
collection logic.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Keep the warning output when linkname symbol is not found,
consistent with main branch behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Reorganize code structure by placing related skip collection
functions (collectSkipNames, collectSkipNamesByDoc, collectSkip)
before the linkname collection functions for better readability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Remove dead commented code that was left over from previous implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rtFunc() does not resolve go:linkname for runtime/internal/runtime package

1 participant