Skip to content

build: make c-shared and c-archive outputs usable from C#2083

Merged
xushiwei merged 9 commits into
xgo-dev:mainfrom
cpunion:codex/funcinfo-cshared-relocations
Jul 18, 2026
Merged

build: make c-shared and c-archive outputs usable from C#2083
xushiwei merged 9 commits into
xgo-dev:mainfrom
cpunion:codex/funcinfo-cshared-relocations

Conversation

@cpunion

@cpunion cpunion commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

Problem

ELF c-shared links reject funcinfo metadata relocations because site records contain absolute pointers in non-writable sections. Once exported Go functions are actually retained, the same issue also appears in compiler-emitted PC/line records.

The generated C libraries had several additional usability gaps:

  • c-shared package archives did not retain unreferenced //export functions, so the header declared symbols that were absent from the shared library
  • c-archive stored package .a files as nested archive members, which C linkers cannot search
  • Go array value parameters were emitted as C array parameters, which decay to pointers and mismatch the aggregate value ABI on architectures such as amd64
  • package C sources used by c-shared were not compiled as PIC
  • imported runtime exports and init functions leaked into the public C header
  • stale libuv time callbacks and a Darwin os.executablePath reference prevented runtime-backed C libraries from linking
  • the export demo reported C consumer failures as warnings, so CI could pass without a usable library

Changes

  • make ELF funcinfo entry, stub, and PC/line site sections writable while preserving SHF_LINK_ORDER and GNU retain semantics
  • mark internal symbol-index globals hidden so shared-library links use non-preemptible relative relocations
  • keep every //export symbol as a c-shared linker root on ELF and Mach-O
  • build c-archive outputs with llvm-ar MRI ADDLIB/ADDMOD commands so package archives are flattened into ordinary object members
  • emit generated wrapper structs for Go array value parameters, preserving the platform aggregate ABI instead of relying on decaying C array syntax
  • compile package C/C++ sources with -fPIC for c-shared
  • restrict generated public headers to exports owned by user packages, excluding imported/runtime implementation symbols
  • remove unused libuv time callback wrappers and provide the Darwin weak os.executablePath fallback needed when runtime is linked without os
  • make shared and static C consumer compilation and execution gating in the existing CI demo
  • exercise both output modes from C, including:
    • actual runtime.Callers, CallersFrames, and FuncForPC symbol/file/line lookup
    • a Go goroutine invoked through an exported function
    • Go/C callbacks and void callbacks
    • strings, slices, maps, channels, interfaces, structs, and single-/multi-dimensional arrays
  • verify llvm-ar selection, paths containing spaces, flat archive membership, and tool failures
  • skip the two build-mode checks only when the active Go toolchain is older than the root go.mod requirement

This is a generic C-library and shared-library metadata fix extracted from #2079. It has no TLS/GLS dependency and is based directly on xgo-dev/llgo main.

The separate Go 1.26 standard-library hook gap found with an exported function using fmt.Sprintf is tracked in #2096 and is intentionally not included here.

The ELF Full LTO PC-line anchor issue is handled independently by #2097. When the branches are combined, its local-label anchor must retain this PR's writable awo section flags.

Testing

  • macOS arm64, Go 1.26.5, LLVM 19:
    • _demo/go/export/test.sh passes
    • both the dylib and static archive link into C executables and run through all assertions
    • both consumers retrieve non-empty function name, file, and line information through Callers/FuncForPC
  • Linux arm64 Docker, Go 1.24.2, LLVM 19:
    • _demo/go/export/test.sh passes
    • both the .so and static archive C executables run through the same runtime and ABI assertions
  • package tests and coverage on Go 1.26.5:
    • internal/header: 92.3%; the changed export-filter and missing-export paths are covered
    • internal/build: 71.9%; all new build/header helpers: 100%
    • internal/cabi: 96.4%
    • runtime/internal/clite/libuv compiles successfully
  • after rebasing onto current main, internal/build, internal/header, and internal/cabi pass locally with GOMAXPROCS=2, GOMEMLIMIT=6GiB, and -p=1
  • after rebasing, _demo/go/export/test.sh passes on macOS arm64 and in an Ubuntu arm64 container limited to 15 GiB, 2 CPUs, and 512 PIDs; both shared and static C consumers execute all assertions

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@cpunion
cpunion marked this pull request as ready for review July 14, 2026 00:05
@cpunion
cpunion force-pushed the codex/funcinfo-cshared-relocations branch from 3d99272 to 0b7858b Compare July 15, 2026 10:36
@cpunion cpunion changed the title build: support funcinfo relocations in ELF shared libraries build: make c-shared and c-archive outputs usable from C Jul 15, 2026
@cpunion cpunion added bugfix Fixes an existing bug or regression feature and removed feature labels Jul 16, 2026
@cpunion
cpunion force-pushed the codex/funcinfo-cshared-relocations branch from c1519da to 7858ab9 Compare July 17, 2026 12:44
@xushiwei
xushiwei merged commit 5e16c0d into xgo-dev:main Jul 18, 2026
42 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix Fixes an existing bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants