w6a: branch labels stay out of the symtab (isglobal wired)

Every interned symbol -- including branch labels defined via
p.label -- was emitted STB_GLOBAL, so labels were collide-able
across objects and the header's "GLOBAL symbols only" contract was
enforced nowhere (asym.isglobal was set but never read). Labels
stay interned for fixup resolution; the symtab now carries only
exported definitions, undefined externs, and reloc-referenced syms
(a reloc pre-pass marks those). rt/ensure.o drops from 15 emitted
syms to 2. Bootstrap 991-995 hold byte-identical on the new format.
This commit is contained in:
2026-08-09 01:07:19 +09:00
parent 06c40a8bef
commit 4fe2e25da4
4 changed files with 29 additions and 4 deletions

View File

@@ -50,7 +50,8 @@ struct Asym {
int defined; /* 1 if we own its address */
int is_text; /* if 1, address is in .text */
int is_data; /* if 1, address is in .data (mutually exclusive with is_text) */
int is_global; /* exported (TEXT) */
int is_global; /* exported (TEXT/DATA/DATAW) */
int has_reloc; /* referenced by a relocation — must be in the symtab */
u64 addr; /* offset within section if defined */
int idx; /* ELF symtab index, filled at emit time */
Asym *next;

View File

@@ -13,9 +13,9 @@
* omitted entirely so output stays byte-identical to the pre-DATAW
* format. Test 991 (selfhost .o byte-diff) depends on this.
*
* Symtab indices: 0 = STN_UNDEF, 1 = file (skipped), 2.. = our syms.
* For simplicity we emit GLOBAL symbols only (no LOCAL ordering rules
* to worry about).
* Symtab indices: 0 = STN_UNDEF, 1.. = our syms (no file entry).
* Every emitted symbol is GLOBAL (no LOCAL ordering rules); defined
* non-exported label syms are pruned unless a reloc references them.
*/
#include "a.h"
#include <stdlib.h>
@@ -156,8 +156,17 @@ a_emit_elf(Asm *a, FILE *f)
/* Data symbols carry STT_OBJECT and st_shndx=SH_DATA; everything
* else keeps the legacy STT_FUNC/SH_TEXT shape so non-DATAW
* outputs stay byte-identical. */
/* Branch labels are interned for fixup resolution but are NOT
* link-visible: emitting them (all bindings here are GLOBAL)
* made every label collide-able across objects. Only exported
* definitions (is_global), undefined externs, and reloc-
* referenced syms reach the symtab. */
for (Areloc *r = a->relocs; r; r = r->next)
r->sym->has_reloc = 1;
int idx = 1;
for (Asym *s = a->syms; s; s = s->next) {
if (s->defined && !s->is_global && !s->has_reloc)
continue;
Sym64 e = {0};
e.st_name = stput(&str, s->name);
if (s->defined) {

View File

@@ -187,9 +187,23 @@ export fn emitelf(a: *asm_, fd: i32) i32 = {
for (zi < 24) { zsym[zi] = 0u8; zi += 1; };
bufputb(&sym, zsym.ptr, 24u64);
// Branch labels are interned for fixup resolution but are NOT
// link-visible: emitting them (all bindings here are GLOBAL)
// made every label collide-able across objects. Only exported
// definitions (isglobal), undefined externs, and reloc-
// referenced syms reach the symtab.
let rr: *areloc = a.relocs;
for (rr != nil) {
rr.asy.hasreloc = 1;
rr = rr.rnext;
};
let idx: i32 = 1;
let s: *asym = a.syms;
for (s != nil) {
if (s.defined != 0 && s.isglobal == 0 && s.hasreloc == 0) {
s = s.snext;
continue;
};
let entry: [24]u8;
let ei: i32 = 0;
for (ei < 24) { entry[ei] = 0u8; ei += 1; };

View File

@@ -170,6 +170,7 @@ type asym = struct {
istext: i32,
isdata: i32, // mutually exclusive with istext; DATAW symbols
isglobal: i32,
hasreloc: i32, // referenced by a relocation — must be in the symtab
addr: u64, // offset within its section (.text or .data)
idx: i32,
snext: *asym,