Skip to content

Define Linking ABI for common symbols#267

Open
dschuff wants to merge 1 commit into
mainfrom
common-symbol
Open

Define Linking ABI for common symbols#267
dschuff wants to merge 1 commit into
mainfrom
common-symbol

Conversation

@dschuff

@dschuff dschuff commented May 22, 2026

Copy link
Copy Markdown
Member

As discussed in llvm/llvm-project#196641

So far there is not support for initialized common symbols.

As discussed in llvm/llvm-project#196641
So far there is not support for initialized common symbols.
@dschuff
dschuff requested a review from sbc100 May 22, 2026 00:44
@dschuff

dschuff commented May 22, 2026

Copy link
Copy Markdown
Member Author

I have an implementation which I will post shortly.

@sbc100 This version uses the combined bitmask of BINDING_GLOBAL and BINDING_WEAK (which are mutually exclusive) to mean BINDING_COMMON. Do you think this is better than just allocating another bit at the end?

@sbc100

sbc100 commented May 22, 2026

Copy link
Copy Markdown
Member

Combining BINDING_GLOBAL and BINDING_WEAK makes some logical sense to me.

But I don't quite understand since WASM_SYM_BINDING_GLOBAL is zero how can you know if its included in the bitmask along with WASM_SYM_BINDING_WEAK?

@dschuff

dschuff commented May 22, 2026

Copy link
Copy Markdown
Member Author

Sorry, I meant the combination of BINDING_LOCAL (0b01) and BINDING_WEAK(0b10), means BINDING_COMMON (0b11). Currently LOCAL is exclusive with WEAK (explicitly disallowed in the current doc), and of course both of those are exclusive with GLOBAL by the construction of the encoding.

@sbc100

sbc100 commented May 22, 2026

Copy link
Copy Markdown
Member

Yes, I suppose LOCAL + WEAK is less intuitive.. is it hard to add another bit to the encoding?

@dschuff

dschuff commented May 22, 2026

Copy link
Copy Markdown
Member Author

No, I don't think it would be. With the current formulation, the first 2 bits encode one of 4 possible bindings, which become mutually exclusive by construction. That's nice; but the downside is that these are no longer one-bit "flags" in the same sense that the rest of the bits are now. And of course if we ever add another binding, then it will be even weirder, since we'll have these 4 possibilities, plus another bit.

@dschuff

dschuff commented Jul 15, 2026

Copy link
Copy Markdown
Member Author

Based on our last conversation, I think we decided that combining the bits as described here (rather than adding more) was ok, but you also mentioned comparing to the way ELF does it. Here's the LLM's summary of the differences:

Dimension ELF LLD Wasm LLD (Current Implementation)
Resolution Timing Early: Replaces CommonSymbols with Defined symbols pointing to dummy BssSections immediately after symbol resolution. Late: Retains CommonSymbol representation until the Writer pass begins, only performing the allocation at layout time.
Section Granularity Fine-grained: Creates a separate BssSection for each common symbol. Coarse-grained: Groups all prevailing common symbols into a single synthetic .bss.common segment.
Relocatable Link (-r) Allocates symbols to temporary BssSections, and attempts to write them back as SHN_COMMON in the output symbol table. Bypasses allocation entirely (returns early in allocateCommonSymbols), leaving them unallocated.

Keeping COMMON as a property of the symbol (rather than replacing with a defined symbol) seems cleaner to me? But not sure about that, I'm willing to defer to your opinion

Gemini claims the ELF approach also results in problems when linking with -r (although that's admittedly a niche use case):

ELF's Relocatable Link Bug
Because ELF LLD performs early replacement, it has a known flaw when linking with -r:

  1. It replaces common symbols with BssSections named "COMMON".
  2. When writing the relocatable output, the symbol table writer correctly restores their section index to SHN_COMMON (unallocated).
  3. The Bug: However, LLD still emits the dummy "COMMON" input sections into the output file. When you link this relocatable object again to produce an executable, the linker sees both the SHN_COMMON symbol and the empty "COMMON" sections, leading to double allocation (allocating space for both).
    Our Wasm implementation is structurally cleaner because it avoids early replacement and cleanly bypasses allocation in -r mode.

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.

2 participants