w6a+w6l: DATAR directive for absolute-address relocs in .data

Unblock literal initialisers for str/slice/struct globals by wiring
an R_X86_64_64 relocation kind through both assembler and static
linker.

w6a:
  - new A_DATAR directive, syntax `DATAR slot+off(SB),target(SB)`,
    records an R_X86_64_64 reloc at slot+off in .data pointing at
    target. The slot must be pre-defined by a prior DATAW;
  - parse_operand learned the `name+disp(SB)` shape so the slot's
    byte offset can be addressed explicitly;
  - Areloc carries a `section` flag (0=.text / 1=.data) and obj.c
    splits the reloc list into .rela.text and .rela.data, emitting
    the latter conditionally with sh_info pointing at .data.

w6l:
  - Lrel grows the same `section` flag; obj.c loads `.rela.data`
    sections into the global reloc list with offsets shifted by
    each input's data_off;
  - pass.c handles R_X86_64_64: target VA is data_va+sym.val for
    in_data symbols (else text_va+sym.val), addend is added, and
    the 8-byte slot is patched in l->data (or l->text).

Inputs without DATAR are unaffected — bootstrap, 991 (selfhost .o
diff) and 992 (selfhost exe diff) keep their byte-identical
output. 520_datar covers the new path: asm a DATAW+DATAR pair,
verify .rela.data has exactly one R_X86_64_64 entry, link, run,
confirm the relocated pointer feeds a 5-byte write that prints
"hello".

Selfhost mirror + w6c emission for str/slice/struct literal init
land in follow-ups.
This commit is contained in:
2026-05-12 12:45:11 +09:00
parent 00d1120441
commit d998425391
11 changed files with 353 additions and 21 deletions

View File

@@ -13,6 +13,7 @@
#include <stdio.h>
#include <string.h>
#define R_X86_64_64 1
#define R_X86_64_PC32 2
#define R_X86_64_PLT32 4
@@ -67,6 +68,13 @@ patch_u32(u8 *p, u32 v)
p[3] = (u8)((v >> 24) & 0xff);
}
static void
patch_u64(u8 *p, u64 v)
{
for (int i = 0; i < 8; i++)
p[i] = (u8)((v >> (i * 8)) & 0xff);
}
int
l_relocate(Lnk *l, u64 text_va, u64 data_va)
{
@@ -76,17 +84,31 @@ l_relocate(Lnk *l, u64 text_va, u64 data_va)
* PLT's virtual address is known. */
if (r->sym->is_dyn) continue;
if (!r->sym->defined) continue;
u64 sym_va = r->sym->in_data
? data_va + r->sym->val
: text_va + r->sym->val;
switch (r->kind) {
case R_X86_64_PC32:
case R_X86_64_PLT32: {
/* PC-relative 32-bit displacement; lands in .text. */
u64 site = text_va + r->off;
u64 sym_va = r->sym->in_data
? data_va + r->sym->val
: text_va + r->sym->val;
i64 rel = (i64)sym_va - (i64)site + r->addend;
patch_u32(l->text + r->off, (u32)(i32)rel);
break;
}
case R_X86_64_64: {
/* Absolute 64-bit: patch the 8-byte slot at the
* given offset within the section. Currently only
* used for data slots holding symbol addresses
* (DATAR). */
u64 v = (u64)((i64)sym_va + r->addend);
if (r->section == 1) {
patch_u64(l->data + r->off, v);
} else {
patch_u64(l->text + r->off, v);
}
break;
}
default:
fprintf(stderr, "w6l: unsupported reloc kind %d\n",
r->kind);