link_script.c (52291B)
1 /* Linker-script parser: a minimal GNU-ld-subset front end that produces 2 * the structured KitLinkScript form documented in <kit/link.h>. The 3 * applicator (link_layout.c) consumes the structured form; this file 4 * never speaks ELF or layout. 5 * 6 * Subset (driven by the kernel.lds at the head of doc/DESIGN.md §13): 7 * ENTRY(symbol) 8 * SECTIONS { ... } 9 * . = expr 10 * name = expr 11 * name : [ALIGN(N)] { body } 12 * /DISCARD/ : { body } 13 * body items: *(p1 p2 ...), name = expr, . = expr 14 * exprs: int literal (dec / 0x), `.`, ident, parens, 15 * + - * / & | ^ << >>, 16 * ALIGN(align) (1-arg: aligns `.`, GNU form) 17 * ALIGN(val, align) (2-arg: aligns an explicit expr) 18 * slash-star comments; whitespace insensitive. 19 * 20 * Anything else (MEMORY, PROVIDE, KEEP, AT>, > REGION, OVERLAY, INSERT, 21 * OUTPUT_FORMAT, INPUT, GROUP, MAX, MIN, line comments, quoted strings, 22 * file patterns other than the implicit `*` of `*(...)`) is a parse 23 * error: emits a diagnostic and returns 1, leaving *out unchanged. 24 * 25 * Encoding contracts the applicator relies on: 26 * - /DISCARD/ is encoded as a KitLinkOutputSection with name 27 * "/DISCARD/" (a literal sentinel, not a parsed identifier). 28 * - An output section's `: ALIGN(N)` header is encoded as the first 29 * entry in its asns[]: a dot-assignment whose expr is ALIGN(., N). 30 * - `*(p1 p2 ...)` produces one KitLinkInputMatch per pattern with 31 * file_pattern = empty slice (implicit `*`) and section_pattern set. 32 * COMMON is parsed as a literal pattern "COMMON". 33 * 34 * Allocation: every node and string is owned by the compiler's tu arena. 35 * kit_link_script_free is therefore a no-op — the arena outlives the 36 * script and is collectively freed with the compiler. During parsing we 37 * grow temporary arrays on the host heap, then arena-copy at finish. 38 * 39 * Diagnostics: SourceManager registration of a script buffer is a future 40 * cleanup; for now diagnostics carry file_id = 0 and pack the byte 41 * offset into the SrcLoc.line field (col is computed inline). */ 42 43 #include <kit/core.h> 44 #include <kit/link.h> 45 #include <stdarg.h> 46 #include <stddef.h> 47 #include <string.h> 48 49 #include "core/arena.h" 50 #include "core/core.h" 51 #include "core/diag.h" 52 #include "core/heap.h" 53 #include "core/slice.h" 54 #include "core/util.h" 55 56 /* The public KitLinkScript has no place to carry its backing-arena 57 * pointer, so we allocate a fixed-shape owner block via heap and arena- 58 * init it inline. kit_link_script_free recovers the owner by stepping 59 * back from the script field to the wrapping struct. The arena's first 60 * member must match struct Arena (defined in core/arena.h). */ 61 typedef struct ScriptOwner { 62 Arena arena; 63 KitLinkScript script; 64 } ScriptOwner; 65 66 typedef struct LSP { 67 Arena* arena; 68 Heap* heap; 69 KitDiagSink* diag; 70 const char* src; 71 size_t len; 72 size_t pos; 73 /* one-bit error sticky: any diagnostic flips this and the parser 74 * unwinds without producing partial output. */ 75 int err; 76 /* expression-parse recursion depth (parens / unary / binop RHS); guards the 77 * descent from overflowing the C stack on pathological input. */ 78 int expr_depth; 79 } LSP; 80 81 /* Maximum expression nesting depth for both parse and eval. Past this we emit 82 * a clean diagnostic instead of recursing into a stack overflow. */ 83 #define LSP_MAX_EXPR_DEPTH 256 84 85 /* ---- diagnostics ---- */ 86 87 static SrcLoc lsp_loc(const LSP* p, size_t off) { 88 /* TODO: register the script buffer with SourceManager so diagnostics 89 * carry a real file_id; until then encode the byte offset as `line` 90 * and recompute a 1-based line/col on demand. */ 91 SrcLoc l; 92 size_t i, line = 1, col = 1; 93 l.file_id = 0; 94 for (i = 0; i < off && i < p->len; ++i) { 95 if (p->src[i] == '\n') { 96 ++line; 97 col = 1; 98 } else { 99 ++col; 100 } 101 } 102 l.line = (u32)line; 103 l.col = (u32)col; 104 return l; 105 } 106 107 static void lsp_errf(LSP* p, size_t off, const char* fmt, ...) { 108 va_list ap; 109 if (!p->diag) { 110 p->err = 1; 111 return; 112 } 113 va_start(ap, fmt); 114 diag_emitv(p->diag, DIAG_ERROR, lsp_loc(p, off), fmt, ap); 115 va_end(ap); 116 p->err = 1; 117 } 118 119 /* ---- arena helpers ---- */ 120 121 static char* lsp_strdup(LSP* p, const char* s, size_t n) { 122 return arena_strdup(p->arena, s, n); 123 } 124 125 /* Arena-copy a span of the script text and return a KitSlice over the 126 * copy. The copy is NUL-terminated (arena_strdup), so consumers that hit 127 * a host boundary can use .s directly. */ 128 static KitSlice lsp_slice(LSP* p, const char* s, size_t n) { 129 KitSlice out; 130 out.s = lsp_strdup(p, s, n); 131 out.len = out.s ? n : 0; 132 return out; 133 } 134 135 static KitLinkExpr* lsp_new_expr(LSP* p) { 136 return arena_znew(p->arena, KitLinkExpr); 137 } 138 139 /* ---- heap-backed temp vectors (copied to the arena at finish) ---- */ 140 141 typedef struct VecAsn { 142 KitLinkAssignment* p; 143 u32 n, cap; 144 } VecAsn; 145 typedef struct VecMatch { 146 KitLinkInputMatch* p; 147 u32 n, cap; 148 } VecMatch; 149 typedef struct VecSec { 150 KitLinkOutputSection* p; 151 u32 n, cap; 152 } VecSec; 153 typedef struct VecRegion { 154 KitLinkRegion* p; 155 u32 n, cap; 156 } VecRegion; 157 typedef struct VecPhdr { 158 KitLinkPhdr* p; 159 u32 n, cap; 160 } VecPhdr; 161 typedef struct VecAssert { 162 KitLinkAssertion* p; 163 u32 n, cap; 164 } VecAssert; 165 typedef struct VecSlice { 166 KitSlice* p; 167 u32 n, cap; 168 } VecSlice; 169 170 static int vec_reserve_(LSP* p, void** ptr, u32* cap, u32 want, size_t es) { 171 u32 nc; 172 void* nb; 173 if (*cap >= want) return 0; 174 nc = *cap ? *cap * 2 : 8; 175 while (nc < want) nc *= 2; 176 nb = p->heap->realloc(p->heap, *ptr, (size_t)*cap * es, (size_t)nc * es, 177 sizeof(void*)); 178 if (!nb) return 1; 179 *ptr = nb; 180 *cap = nc; 181 return 0; 182 } 183 184 #define VEC_PUSH(p, v, val) \ 185 (vec_reserve_((p), (void**)&(v).p, &(v).cap, (v).n + 1, sizeof(*(v).p)) \ 186 ? 1 \ 187 : ((v).p[(v).n++] = (val), 0)) 188 189 static void vec_free_(LSP* p, void* ptr, u32 cap, size_t es) { 190 if (ptr) p->heap->free(p->heap, ptr, (size_t)cap * es); 191 } 192 193 /* ---- lex primitives ---- */ 194 195 static int is_id_start(int c) { 196 return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || 197 c == '.'; 198 } 199 static int is_id_cont(int c) { 200 return is_id_start(c) || (c >= '0' && c <= '9') || c == '-'; 201 } 202 203 static void skip_ws(LSP* p) { 204 while (p->pos < p->len) { 205 char ch = p->src[p->pos]; 206 if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') { 207 ++p->pos; 208 continue; 209 } 210 if (ch == '/' && p->pos + 1 < p->len && p->src[p->pos + 1] == '*') { 211 size_t start = p->pos; 212 p->pos += 2; 213 while (p->pos + 1 < p->len && 214 !(p->src[p->pos] == '*' && p->src[p->pos + 1] == '/')) { 215 ++p->pos; 216 } 217 if (p->pos + 1 >= p->len) { 218 lsp_errf(p, start, "unterminated /* comment"); 219 return; 220 } 221 p->pos += 2; 222 continue; 223 } 224 if (ch == '/' && p->pos + 1 < p->len && p->src[p->pos + 1] == '/') { 225 lsp_errf(p, p->pos, "// line comments not supported"); 226 return; 227 } 228 break; 229 } 230 } 231 232 static int peek_ch(LSP* p) { 233 skip_ws(p); 234 if (p->err) return -1; 235 if (p->pos >= p->len) return -1; 236 return (unsigned char)p->src[p->pos]; 237 } 238 239 static int match_ch(LSP* p, char ch) { 240 skip_ws(p); 241 if (p->err) return 0; 242 if (p->pos < p->len && p->src[p->pos] == ch) { 243 ++p->pos; 244 return 1; 245 } 246 return 0; 247 } 248 249 static int expect_ch(LSP* p, char ch) { 250 if (match_ch(p, ch)) return 0; 251 lsp_errf(p, p->pos, "expected '%c'", ch); 252 return 1; 253 } 254 255 /* Lex an identifier-or-section-name token in place: returns a pointer 256 * into p->src and length via *out_len. Section names like .text.* and 257 * /DISCARD/ are handled by the section-name-aware variant below. */ 258 static int lex_ident(LSP* p, const char** out, size_t* out_len) { 259 size_t start; 260 skip_ws(p); 261 if (p->err) return 1; 262 if (p->pos >= p->len || !is_id_start((unsigned char)p->src[p->pos])) { 263 lsp_errf(p, p->pos, "expected identifier"); 264 return 1; 265 } 266 start = p->pos; 267 while (p->pos < p->len && is_id_cont((unsigned char)p->src[p->pos])) ++p->pos; 268 *out = p->src + start; 269 *out_len = p->pos - start; 270 return 0; 271 } 272 273 static int lex_string(LSP* p, KitSlice* out) { 274 size_t start; 275 skip_ws(p); 276 if (p->err) return 1; 277 if (p->pos >= p->len || p->src[p->pos] != '"') { 278 lsp_errf(p, p->pos, "expected string literal"); 279 return 1; 280 } 281 ++p->pos; 282 start = p->pos; 283 while (p->pos < p->len && p->src[p->pos] != '"') { 284 if (p->src[p->pos] == '\\') { 285 lsp_errf(p, p->pos, "escapes in linker-script strings not supported"); 286 return 1; 287 } 288 ++p->pos; 289 } 290 if (p->pos >= p->len) { 291 lsp_errf(p, start, "unterminated string literal"); 292 return 1; 293 } 294 *out = lsp_slice(p, p->src + start, p->pos - start); 295 ++p->pos; 296 return out->s ? 0 : 1; 297 } 298 299 static int lex_ident_or_string(LSP* p, KitSlice* out) { 300 int ch; 301 skip_ws(p); 302 if (p->err) return 1; 303 ch = peek_ch(p); 304 if (ch == '"') return lex_string(p, out); 305 { 306 const char* s; 307 size_t n; 308 if (lex_ident(p, &s, &n)) return 1; 309 *out = lsp_slice(p, s, n); 310 return out->s ? 0 : 1; 311 } 312 } 313 314 /* Match a literal keyword. Caller must have already peeked. */ 315 static int match_kw(LSP* p, const char* kw) { 316 size_t klen = slice_from_cstr(kw).len; 317 size_t save; 318 skip_ws(p); 319 if (p->err) return 0; 320 save = p->pos; 321 if (p->pos + klen > p->len) return 0; 322 if (memcmp(p->src + p->pos, kw, klen) != 0) return 0; 323 /* must not glue to a following id-cont character */ 324 if (p->pos + klen < p->len && 325 is_id_cont((unsigned char)p->src[p->pos + klen])) 326 return 0; 327 p->pos += klen; 328 (void)save; 329 return 1; 330 } 331 332 /* ---- expression parser (precedence climbing) ---- 333 * 334 * Levels (low -> high): 335 * 0: | 336 * 1: ^ 337 * 2: & 338 * 3: << >> 339 * 4: + - 340 * 5: * / 341 * 6: unary (none beyond parenthesized atoms here) 342 * atom: int | . | ALIGN(e,a) | ident | (expr) 343 */ 344 345 static KitLinkExpr* parse_expr(LSP* p); 346 static KitLinkExpr* parse_atom(LSP* p); 347 348 static KitLinkExpr* parse_int(LSP* p) { 349 KitLinkExpr* e; 350 size_t start = p->pos; 351 /* Accumulate unsigned: linker-script addresses routinely set the top bit 352 * (e.g. 0xFFFFFFFF80000000 high-half kernels); a signed shift/multiply would 353 * be UB there. The value is a bit pattern, reinterpreted into int_val below. */ 354 u64 v = 0; 355 if (p->pos + 1 < p->len && p->src[p->pos] == '0' && 356 (p->src[p->pos + 1] == 'x' || p->src[p->pos + 1] == 'X')) { 357 p->pos += 2; 358 if (p->pos >= p->len) { 359 lsp_errf(p, start, "malformed hex literal"); 360 return NULL; 361 } 362 while (p->pos < p->len) { 363 char ch = p->src[p->pos]; 364 int d; 365 if (ch >= '0' && ch <= '9') 366 d = ch - '0'; 367 else if (ch >= 'a' && ch <= 'f') 368 d = 10 + (ch - 'a'); 369 else if (ch >= 'A' && ch <= 'F') 370 d = 10 + (ch - 'A'); 371 else 372 break; 373 v = (v << 4) | d; 374 ++p->pos; 375 } 376 if (p->pos == start + 2) { 377 lsp_errf(p, start, "empty hex literal"); 378 return NULL; 379 } 380 } else { 381 while (p->pos < p->len && p->src[p->pos] >= '0' && p->src[p->pos] <= '9') { 382 v = v * 10 + (p->src[p->pos] - '0'); 383 ++p->pos; 384 } 385 if (p->pos == start) { 386 lsp_errf(p, start, "expected integer"); 387 return NULL; 388 } 389 } 390 if (p->pos < p->len) { 391 char suffix = p->src[p->pos]; 392 if (suffix == 'K' || suffix == 'k') { 393 v *= 1024ull; 394 ++p->pos; 395 } else if (suffix == 'M' || suffix == 'm') { 396 v *= 1024ull * 1024ull; 397 ++p->pos; 398 } else if (suffix == 'G' || suffix == 'g') { 399 v *= 1024ull * 1024ull * 1024ull; 400 ++p->pos; 401 } 402 } 403 e = lsp_new_expr(p); 404 if (!e) return NULL; 405 e->kind = KIT_LE_INT; 406 e->v.int_val = (i64)v; 407 return e; 408 } 409 410 static KitLinkExpr* parse_atom_inner(LSP* p) { 411 int ch; 412 skip_ws(p); 413 if (p->err) return NULL; 414 ch = peek_ch(p); 415 if (ch < 0) { 416 lsp_errf(p, p->pos, "unexpected end of expression"); 417 return NULL; 418 } 419 if (ch == '-' || ch == '+') { 420 int neg = (ch == '-'); 421 KitLinkExpr* val; 422 KitLinkExpr* e; 423 ++p->pos; 424 val = parse_atom(p); 425 if (!val) return NULL; 426 if (!neg) return val; 427 e = lsp_new_expr(p); 428 if (!e) return NULL; 429 e->kind = KIT_LE_NEG; 430 e->v.align.val = val; 431 e->v.align.align = NULL; 432 return e; 433 } 434 if (ch == '(') { 435 KitLinkExpr* e; 436 ++p->pos; 437 e = parse_expr(p); 438 if (!e) return NULL; 439 if (expect_ch(p, ')')) return NULL; 440 return e; 441 } 442 if (ch == '.') { 443 /* `.` only — bare dot, not a dotted ident. We disambiguate by 444 * looking at the next char: a digit/letter/underscore/dot here is a 445 * lex error in this subset (no .text in expression position). */ 446 size_t off = p->pos; 447 ++p->pos; 448 if (p->pos < p->len && is_id_cont((unsigned char)p->src[p->pos])) { 449 lsp_errf(p, off, "dotted identifiers not allowed in expressions"); 450 return NULL; 451 } 452 { 453 KitLinkExpr* e = lsp_new_expr(p); 454 if (!e) return NULL; 455 e->kind = KIT_LE_DOT; 456 return e; 457 } 458 } 459 if (ch >= '0' && ch <= '9') return parse_int(p); 460 if (is_id_start(ch)) { 461 /* either a built-in helper or a symbol reference */ 462 if (match_kw(p, "ALIGN") || match_kw(p, "BLOCK")) { 463 /* Two forms, matching GNU ld: 464 * ALIGN(align) — align the current location `.` (val defaults 465 * to dot); the common `. = ALIGN(N)` idiom. 466 * ALIGN(val, align) — align an explicit expression. */ 467 KitLinkExpr *val, *aln, *e; 468 KitLinkExprKind kind = 469 (memcmp(p->src + p->pos - 5, "BLOCK", 5) == 0) ? KIT_LE_BLOCK 470 : KIT_LE_ALIGN; 471 if (expect_ch(p, '(')) return NULL; 472 val = parse_expr(p); 473 if (!val) return NULL; 474 skip_ws(p); 475 if (p->pos < p->len && p->src[p->pos] == ',') { 476 ++p->pos; 477 aln = parse_expr(p); 478 if (!aln) return NULL; 479 } else { 480 /* 1-arg form: the parsed expr is the alignment; val is `.`. */ 481 aln = val; 482 val = lsp_new_expr(p); 483 if (!val) return NULL; 484 val->kind = KIT_LE_DOT; 485 } 486 if (expect_ch(p, ')')) return NULL; 487 e = lsp_new_expr(p); 488 if (!e) return NULL; 489 e->kind = (uint8_t)kind; 490 e->v.align.val = val; 491 e->v.align.align = aln; 492 return e; 493 } 494 if (match_kw(p, "MAX") || match_kw(p, "MIN")) { 495 KitLinkExprKind kind = 496 (memcmp(p->src + p->pos - 3, "MIN", 3) == 0) ? KIT_LE_MIN 497 : KIT_LE_MAX; 498 KitLinkExpr *lhs, *rhs, *e; 499 if (expect_ch(p, '(')) return NULL; 500 lhs = parse_expr(p); 501 if (!lhs) return NULL; 502 if (expect_ch(p, ',')) return NULL; 503 rhs = parse_expr(p); 504 if (!rhs) return NULL; 505 if (expect_ch(p, ')')) return NULL; 506 e = lsp_new_expr(p); 507 if (!e) return NULL; 508 e->kind = (uint8_t)kind; 509 e->v.bin.lhs = lhs; 510 e->v.bin.rhs = rhs; 511 return e; 512 } 513 if (match_kw(p, "ORIGIN") || match_kw(p, "LENGTH") || 514 match_kw(p, "ADDR") || match_kw(p, "LOADADDR") || 515 match_kw(p, "SIZEOF") || match_kw(p, "DEFINED")) { 516 size_t end = p->pos; 517 size_t start = end; 518 KitLinkExprKind kind; 519 const char* s; 520 size_t n; 521 KitLinkExpr* e; 522 while (start > 0 && is_id_cont((unsigned char)p->src[start - 1])) 523 --start; 524 if (end - start == 6 && memcmp(p->src + start, "ORIGIN", 6) == 0) 525 kind = KIT_LE_REGION_ORIGIN; 526 else if (end - start == 6 && memcmp(p->src + start, "LENGTH", 6) == 0) 527 kind = KIT_LE_REGION_LENGTH; 528 else if (end - start == 4 && memcmp(p->src + start, "ADDR", 4) == 0) 529 kind = KIT_LE_ADDR; 530 else if (end - start == 8 && memcmp(p->src + start, "LOADADDR", 8) == 0) 531 kind = KIT_LE_LOADADDR; 532 else if (end - start == 6 && memcmp(p->src + start, "SIZEOF", 6) == 0) 533 kind = KIT_LE_SIZEOF; 534 else 535 kind = KIT_LE_DEFINED; 536 if (expect_ch(p, '(')) return NULL; 537 if (lex_ident(p, &s, &n)) return NULL; 538 if (expect_ch(p, ')')) return NULL; 539 e = lsp_new_expr(p); 540 if (!e) return NULL; 541 e->kind = (uint8_t)kind; 542 e->v.name = lsp_slice(p, s, n); 543 return e; 544 } 545 if (match_kw(p, "SIZEOF_HEADERS")) { 546 KitLinkExpr* e; 547 if (match_ch(p, '(')) { 548 if (expect_ch(p, ')')) return NULL; 549 } 550 e = lsp_new_expr(p); 551 if (!e) return NULL; 552 e->kind = KIT_LE_SIZEOF_HEADERS; 553 return e; 554 } 555 if (match_kw(p, "ABSOLUTE")) { 556 KitLinkExpr *val, *e; 557 if (expect_ch(p, '(')) return NULL; 558 val = parse_expr(p); 559 if (!val) return NULL; 560 if (expect_ch(p, ')')) return NULL; 561 e = lsp_new_expr(p); 562 if (!e) return NULL; 563 e->kind = KIT_LE_ABSOLUTE; 564 e->v.align.val = val; 565 e->v.align.align = NULL; 566 return e; 567 } 568 { 569 const char* s; 570 size_t n; 571 KitLinkExpr* e; 572 if (lex_ident(p, &s, &n)) return NULL; 573 e = lsp_new_expr(p); 574 if (!e) return NULL; 575 e->kind = KIT_LE_SYM; 576 e->v.name = lsp_slice(p, s, n); 577 return e; 578 } 579 } 580 lsp_errf(p, p->pos, "unexpected '%c' in expression", (char)ch); 581 return NULL; 582 } 583 584 /* Depth-guarded entry to atom parsing. Every nesting level (parens, unary, 585 * binop RHS, helper-call argument) descends through parse_atom, so bumping the 586 * counter here bounds total expression-parse recursion. */ 587 static KitLinkExpr* parse_atom(LSP* p) { 588 KitLinkExpr* e; 589 if (p->err) return NULL; 590 if (++p->expr_depth > LSP_MAX_EXPR_DEPTH) { 591 lsp_errf(p, p->pos, "linker-script expression nested too deeply (>%d)", 592 LSP_MAX_EXPR_DEPTH); 593 --p->expr_depth; 594 return NULL; 595 } 596 e = parse_atom_inner(p); 597 --p->expr_depth; 598 return e; 599 } 600 601 /* Returns >=0 binding power for a binary operator at p->pos and 602 * advances past it; -1 if no binary operator at the lookahead. */ 603 static int try_take_binop(LSP* p, KitLinkExprKind* out_kind) { 604 int ch; 605 skip_ws(p); 606 if (p->err) return -1; 607 if (p->pos >= p->len) return -1; 608 ch = (unsigned char)p->src[p->pos]; 609 switch (ch) { 610 case '|': 611 ++p->pos; 612 *out_kind = KIT_LE_OR; 613 return 0; 614 case '^': 615 ++p->pos; 616 *out_kind = KIT_LE_XOR; 617 return 1; 618 case '&': 619 ++p->pos; 620 *out_kind = KIT_LE_AND; 621 return 2; 622 case '<': 623 if (p->pos + 1 < p->len && p->src[p->pos + 1] == '<') { 624 p->pos += 2; 625 *out_kind = KIT_LE_SHL; 626 return 3; 627 } 628 return -1; 629 case '>': 630 if (p->pos + 1 < p->len && p->src[p->pos + 1] == '>') { 631 p->pos += 2; 632 *out_kind = KIT_LE_SHR; 633 return 3; 634 } 635 return -1; 636 case '+': 637 ++p->pos; 638 *out_kind = KIT_LE_ADD; 639 return 4; 640 case '-': 641 ++p->pos; 642 *out_kind = KIT_LE_SUB; 643 return 4; 644 case '*': 645 ++p->pos; 646 *out_kind = KIT_LE_MUL; 647 return 5; 648 case '/': 649 /* Division. Block-comment and /DISCARD/ openers are filtered 650 * elsewhere: skip_ws eats slash-star comments, and /DISCARD/ is 651 * recognized by the SECTIONS-body loop before expression 652 * context. */ 653 ++p->pos; 654 *out_kind = KIT_LE_DIV; 655 return 5; 656 default: 657 return -1; 658 } 659 } 660 661 static KitLinkExpr* parse_binop_rhs(LSP* p, int min_bp, KitLinkExpr* lhs) { 662 while (!p->err) { 663 size_t save; 664 KitLinkExprKind k; 665 int bp; 666 skip_ws(p); 667 if (p->err) return NULL; 668 save = p->pos; 669 bp = try_take_binop(p, &k); 670 if (bp < 0) return lhs; 671 if (bp < min_bp) { 672 p->pos = save; 673 return lhs; 674 } 675 { 676 KitLinkExpr* rhs = parse_atom(p); 677 KitLinkExpr* node; 678 if (!rhs) return NULL; 679 rhs = parse_binop_rhs(p, bp + 1, rhs); 680 if (!rhs) return NULL; 681 node = lsp_new_expr(p); 682 if (!node) return NULL; 683 node->kind = (uint8_t)k; 684 node->v.bin.lhs = lhs; 685 node->v.bin.rhs = rhs; 686 lhs = node; 687 } 688 } 689 return NULL; 690 } 691 692 static KitLinkExpr* parse_expr(LSP* p) { 693 KitLinkExpr* lhs = parse_atom(p); 694 if (!lhs) return NULL; 695 return parse_binop_rhs(p, 0, lhs); 696 } 697 698 /* ---- assignment helpers ---- */ 699 700 static int push_dot_align(LSP* p, VecAsn* asns, KitLinkExpr* align_n) { 701 KitLinkExpr* dot; 702 KitLinkExpr* aln; 703 KitLinkAssignment a; 704 dot = lsp_new_expr(p); 705 if (!dot) return 1; 706 dot->kind = KIT_LE_DOT; 707 aln = lsp_new_expr(p); 708 if (!aln) return 1; 709 aln->kind = KIT_LE_ALIGN; 710 aln->v.align.val = dot; 711 aln->v.align.align = align_n; 712 memset(&a, 0, sizeof(a)); 713 a.kind = KIT_LAS_DOT; 714 a.sym = KIT_SLICE_NULL; 715 a.expr = aln; 716 return VEC_PUSH(p, *asns, a); 717 } 718 719 /* ---- output section body ---- */ 720 721 static int lex_pattern_token(LSP* p, const char** out, size_t* out_len) { 722 size_t start; 723 skip_ws(p); 724 if (p->err) return 1; 725 start = p->pos; 726 while (p->pos < p->len) { 727 char c = p->src[p->pos]; 728 if (c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '(' || 729 c == ')' || c == '{' || c == '}' || c == ';' || c == ':' || 730 c == ',') 731 break; 732 ++p->pos; 733 } 734 if (p->pos == start) { 735 lsp_errf(p, p->pos, "expected pattern"); 736 return 1; 737 } 738 *out = p->src + start; 739 *out_len = p->pos - start; 740 return 0; 741 } 742 743 static const KitSlice* copy_slice_vec(LSP* p, const VecSlice* v) { 744 KitSlice* arr; 745 if (!v || !v->n) return NULL; 746 arr = arena_array(p->arena, KitSlice, v->n); 747 if (!arr) return NULL; 748 memcpy(arr, v->p, sizeof(*arr) * v->n); 749 return arr; 750 } 751 752 static int parse_file_excludes(LSP* p, VecSlice* excludes) { 753 if (expect_ch(p, '(')) return 1; 754 for (;;) { 755 int ch; 756 const char* s; 757 size_t n; 758 KitSlice sl; 759 skip_ws(p); 760 if (p->err) return 1; 761 ch = peek_ch(p); 762 if (ch == ')') { 763 ++p->pos; 764 return 0; 765 } 766 if (ch < 0) { 767 lsp_errf(p, p->pos, "unterminated EXCLUDE_FILE"); 768 return 1; 769 } 770 if (lex_pattern_token(p, &s, &n)) return 1; 771 sl = lsp_slice(p, s, n); 772 if (!sl.s) return 1; 773 if (VEC_PUSH(p, *excludes, sl)) return 1; 774 } 775 } 776 777 static int parse_input_matchers_for_file(LSP* p, VecMatch* out, 778 KitSlice file_pattern, int keep) { 779 /* expect `(p1 p2 ...)` */ 780 VecSlice excludes = {0}; 781 if (expect_ch(p, '(')) return 1; 782 for (;;) { 783 int ch; 784 skip_ws(p); 785 if (p->err) return 1; 786 ch = peek_ch(p); 787 if (ch == ')') { 788 ++p->pos; 789 vec_free_(p, excludes.p, excludes.cap, sizeof(*excludes.p)); 790 return 0; 791 } 792 if (ch < 0) { 793 lsp_errf(p, p->pos, "unterminated `*(...)`"); 794 goto fail; 795 } 796 if (match_kw(p, "EXCLUDE_FILE")) { 797 if (parse_file_excludes(p, &excludes)) goto fail; 798 continue; 799 } 800 { 801 const char* s; 802 size_t n; 803 KitLinkInputMatch m; 804 if (lex_pattern_token(p, &s, &n)) goto fail; 805 if (n == 0) { 806 lsp_errf(p, p->pos, "expected section pattern"); 807 goto fail; 808 } 809 memset(&m, 0, sizeof(m)); 810 m.file_pattern = file_pattern; 811 m.section_pattern = lsp_slice(p, s, n); 812 m.exclude_file_patterns = copy_slice_vec(p, &excludes); 813 m.nexclude_file_patterns = excludes.n; 814 m.keep = keep; 815 if (excludes.n && !m.exclude_file_patterns) goto fail; 816 if (VEC_PUSH(p, *out, m)) goto fail; 817 } 818 } 819 fail: 820 vec_free_(p, excludes.p, excludes.cap, sizeof(*excludes.p)); 821 return 1; 822 } 823 824 static int parse_input_matchers(LSP* p, VecMatch* out, int keep) { 825 /* opening `*` already consumed by caller. */ 826 return parse_input_matchers_for_file(p, out, KIT_SLICE_NULL, keep); 827 } 828 829 static int parse_assignment_call(LSP* p, KitLinkAsnKind kind, VecAsn* asns) { 830 const char* s; 831 size_t n; 832 KitLinkExpr* e; 833 KitLinkAssignment a; 834 if (expect_ch(p, '(')) return 1; 835 if (lex_ident(p, &s, &n)) return 1; 836 if (expect_ch(p, '=')) return 1; 837 e = parse_expr(p); 838 if (!e) return 1; 839 if (expect_ch(p, ')')) return 1; 840 (void)match_ch(p, ';'); 841 memset(&a, 0, sizeof(a)); 842 a.kind = (uint8_t)kind; 843 a.sym = lsp_slice(p, s, n); 844 a.expr = e; 845 return VEC_PUSH(p, *asns, a); 846 } 847 848 static int parse_assertion(LSP* p, VecAssert* asserts) { 849 KitLinkAssertion a; 850 memset(&a, 0, sizeof(a)); 851 if (expect_ch(p, '(')) return 1; 852 a.expr = parse_expr(p); 853 if (!a.expr) return 1; 854 if (expect_ch(p, ',')) return 1; 855 if (lex_string(p, &a.message)) return 1; 856 if (expect_ch(p, ')')) return 1; 857 (void)match_ch(p, ';'); 858 return VEC_PUSH(p, *asserts, a); 859 } 860 861 static int parse_file_qualified_matchers(LSP* p, VecMatch* inputs, 862 const char* file, size_t file_len, 863 int keep) { 864 KitSlice fp = lsp_slice(p, file, file_len); 865 if (!fp.s) return 1; 866 return parse_input_matchers_for_file(p, inputs, fp, keep); 867 } 868 869 static int parse_section_body(LSP* p, VecMatch* inputs, VecAsn* asns, 870 VecAssert* asserts, KitLinkExpr** fill_out, 871 u32* body_seq) { 872 u32 prev_in = inputs->n; 873 u32 prev_as = asns->n; 874 if (expect_ch(p, '{')) return 1; 875 for (;;) { 876 int ch; 877 /* Stamp the source-order body position onto every input match and 878 * assignment pushed by the previous iteration, then bump for the next 879 * command. One body command (a `*(...)`, a `sym = expr`, a `. = expr`) 880 * may push several input matches (`*(.a .b .c)`) but they all belong to 881 * the same command and share its body_seq. The applicator merge-walks 882 * inputs+asns by body_seq to execute them in true source order. */ 883 while (prev_in < inputs->n) inputs->p[prev_in++].body_seq = *body_seq; 884 while (prev_as < asns->n) asns->p[prev_as++].body_seq = *body_seq; 885 ++*body_seq; 886 skip_ws(p); 887 if (p->err) return 1; 888 ch = peek_ch(p); 889 if (ch == '}') { 890 ++p->pos; 891 return 0; 892 } 893 if (ch < 0) { 894 lsp_errf(p, p->pos, "unterminated section body"); 895 return 1; 896 } 897 if (ch == '*') { 898 ++p->pos; 899 if (parse_input_matchers(p, inputs, 0)) return 1; 900 continue; 901 } 902 if (ch == '.') { 903 /* `. = expr;` */ 904 size_t off = p->pos; 905 ++p->pos; 906 skip_ws(p); 907 if (p->err) return 1; 908 if (!match_ch(p, '=')) { 909 lsp_errf(p, off, "expected `. = expr` in section body"); 910 return 1; 911 } 912 { 913 KitLinkExpr* e = parse_expr(p); 914 KitLinkAssignment a; 915 if (!e) return 1; 916 if (!match_ch(p, ';')) { /* ; is optional but encouraged */ 917 } 918 memset(&a, 0, sizeof(a)); 919 a.kind = KIT_LAS_DOT; 920 a.sym = KIT_SLICE_NULL; 921 a.expr = e; 922 if (VEC_PUSH(p, *asns, a)) return 1; 923 } 924 continue; 925 } 926 if (is_id_start(ch)) { 927 if (match_kw(p, "KEEP")) { 928 const char* fs; 929 size_t fn; 930 if (expect_ch(p, '(')) return 1; 931 skip_ws(p); 932 if (p->err) return 1; 933 if (peek_ch(p) == '*') { 934 ++p->pos; 935 if (parse_input_matchers(p, inputs, 1)) return 1; 936 } else { 937 if (lex_pattern_token(p, &fs, &fn)) return 1; 938 if (parse_file_qualified_matchers(p, inputs, fs, fn, 1)) return 1; 939 } 940 if (expect_ch(p, ')')) return 1; 941 continue; 942 } 943 if (match_kw(p, "FILL")) { 944 if (expect_ch(p, '(')) return 1; 945 *fill_out = parse_expr(p); 946 if (!*fill_out) return 1; 947 if (expect_ch(p, ')')) return 1; 948 (void)match_ch(p, ';'); 949 continue; 950 } 951 if (match_kw(p, "ASSERT")) { 952 if (parse_assertion(p, asserts)) return 1; 953 continue; 954 } 955 if (match_kw(p, "PROVIDE_HIDDEN")) { 956 if (parse_assignment_call(p, KIT_LAS_PROVIDE_HIDDEN, asns)) return 1; 957 continue; 958 } 959 if (match_kw(p, "PROVIDE")) { 960 if (parse_assignment_call(p, KIT_LAS_PROVIDE, asns)) return 1; 961 continue; 962 } 963 if (match_kw(p, "HIDDEN")) { 964 if (parse_assignment_call(p, KIT_LAS_HIDDEN, asns)) return 1; 965 continue; 966 } 967 /* sym = expr; or file(section-patterns) */ 968 const char* s; 969 size_t n; 970 KitLinkExpr* e; 971 KitLinkAssignment a; 972 if (lex_ident(p, &s, &n)) return 1; 973 skip_ws(p); 974 if (p->err) return 1; 975 if (p->pos < p->len && p->src[p->pos] == '(') { 976 if (parse_file_qualified_matchers(p, inputs, s, n, 0)) return 1; 977 continue; 978 } 979 if (!match_ch(p, '=')) { 980 lsp_errf(p, p->pos, "expected `=` after `%.*s`", (int)n, s); 981 return 1; 982 } 983 e = parse_expr(p); 984 if (!e) return 1; 985 (void)match_ch(p, ';'); 986 memset(&a, 0, sizeof(a)); 987 a.kind = KIT_LAS_SYM; 988 a.sym = lsp_slice(p, s, n); 989 a.expr = e; 990 if (VEC_PUSH(p, *asns, a)) return 1; 991 continue; 992 } 993 lsp_errf(p, p->pos, "unexpected '%c' in section body", (char)ch); 994 return 1; 995 } 996 } 997 998 /* ---- output section header ---- */ 999 1000 static int parse_output_section(LSP* p, const char* name_buf, size_t name_len, 1001 KitLinkExpr* vma, bool noload, 1002 VecSec* sections, VecAssert* asserts) { 1003 /* The `:` is the next non-ws char on entry. Header may carry 1004 * `: ALIGN(N)` then `{ body }`. */ 1005 KitLinkOutputSection sec; 1006 VecMatch inputs = {0}; 1007 VecAsn asns = {0}; 1008 VecSlice phdrs = {0}; 1009 KitLinkExpr* align_n = NULL; 1010 KitLinkExpr* subalign = NULL; 1011 KitLinkExpr* fill = NULL; 1012 KitLinkExpr* lma = NULL; 1013 KitLinkExpr* flags = NULL; 1014 KitSlice region = KIT_SLICE_NULL; 1015 KitSlice load_region = KIT_SLICE_NULL; 1016 1017 if (expect_ch(p, ':')) return 1; 1018 for (;;) { 1019 skip_ws(p); 1020 if (p->err) return 1; 1021 if (match_kw(p, "ALIGN")) { 1022 if (expect_ch(p, '(')) return 1; 1023 align_n = parse_expr(p); 1024 if (!align_n) return 1; 1025 if (expect_ch(p, ')')) return 1; 1026 continue; 1027 } 1028 if (match_kw(p, "SUBALIGN")) { 1029 if (expect_ch(p, '(')) return 1; 1030 subalign = parse_expr(p); 1031 if (!subalign) return 1; 1032 if (expect_ch(p, ')')) return 1; 1033 continue; 1034 } 1035 if (match_kw(p, "AT")) { 1036 if (expect_ch(p, '(')) return 1; 1037 lma = parse_expr(p); 1038 if (!lma) return 1; 1039 if (expect_ch(p, ')')) return 1; 1040 continue; 1041 } 1042 if (match_kw(p, "FLAGS")) { 1043 if (expect_ch(p, '(')) return 1; 1044 flags = parse_expr(p); 1045 if (!flags) return 1; 1046 if (expect_ch(p, ')')) return 1; 1047 continue; 1048 } 1049 break; 1050 } 1051 1052 /* Section header alignment is encoded as the first asn — applicator 1053 * pulls it before processing inputs. It runs at body_seq 0 (the section 1054 * base); body commands start at body_seq 1. */ 1055 if (align_n) { 1056 if (push_dot_align(p, &asns, align_n)) goto fail; 1057 asns.p[asns.n - 1].body_seq = 0; 1058 } 1059 1060 { 1061 u32 body_seq = 1; 1062 if (parse_section_body(p, &inputs, &asns, asserts, &fill, &body_seq)) 1063 goto fail; 1064 } 1065 1066 for (;;) { 1067 int ch; 1068 skip_ws(p); 1069 if (p->err) goto fail; 1070 ch = peek_ch(p); 1071 if (ch == ';') { 1072 ++p->pos; 1073 break; 1074 } 1075 if (ch == '>') { 1076 const char* s; 1077 size_t n; 1078 ++p->pos; 1079 if (lex_ident(p, &s, &n)) goto fail; 1080 region = lsp_slice(p, s, n); 1081 if (!region.s) goto fail; 1082 continue; 1083 } 1084 if (ch == ':') { 1085 const char* s; 1086 size_t n; 1087 KitSlice sl; 1088 ++p->pos; 1089 if (lex_ident(p, &s, &n)) goto fail; 1090 sl = lsp_slice(p, s, n); 1091 if (!sl.s) goto fail; 1092 if (VEC_PUSH(p, phdrs, sl)) goto fail; 1093 continue; 1094 } 1095 if (ch == '=') { 1096 ++p->pos; 1097 fill = parse_expr(p); 1098 if (!fill) goto fail; 1099 continue; 1100 } 1101 if (match_kw(p, "AT")) { 1102 const char* s; 1103 size_t n; 1104 if (match_ch(p, '>')) { 1105 if (lex_ident(p, &s, &n)) goto fail; 1106 load_region = lsp_slice(p, s, n); 1107 if (!load_region.s) goto fail; 1108 continue; 1109 } 1110 if (expect_ch(p, '(')) goto fail; 1111 lma = parse_expr(p); 1112 if (!lma) goto fail; 1113 if (expect_ch(p, ')')) goto fail; 1114 continue; 1115 } 1116 if (match_kw(p, "FILL")) { 1117 if (expect_ch(p, '(')) goto fail; 1118 fill = parse_expr(p); 1119 if (!fill) goto fail; 1120 if (expect_ch(p, ')')) goto fail; 1121 continue; 1122 } 1123 break; 1124 } 1125 1126 /* Materialize. */ 1127 { 1128 KitLinkInputMatch* arr_in = NULL; 1129 KitLinkAssignment* arr_as = NULL; 1130 KitSlice* arr_ph = NULL; 1131 if (inputs.n) { 1132 arr_in = arena_array(p->arena, KitLinkInputMatch, inputs.n); 1133 if (!arr_in) goto fail; 1134 memcpy(arr_in, inputs.p, sizeof(*arr_in) * inputs.n); 1135 } 1136 if (asns.n) { 1137 arr_as = arena_array(p->arena, KitLinkAssignment, asns.n); 1138 if (!arr_as) goto fail; 1139 memcpy(arr_as, asns.p, sizeof(*arr_as) * asns.n); 1140 } 1141 if (phdrs.n) { 1142 arr_ph = arena_array(p->arena, KitSlice, phdrs.n); 1143 if (!arr_ph) goto fail; 1144 memcpy(arr_ph, phdrs.p, sizeof(*arr_ph) * phdrs.n); 1145 } 1146 memset(&sec, 0, sizeof(sec)); 1147 sec.name = lsp_slice(p, name_buf, name_len); 1148 sec.vma = vma; 1149 sec.lma = lma; 1150 sec.inputs = arr_in; 1151 sec.ninputs = inputs.n; 1152 sec.region = region; 1153 sec.load_region = load_region; 1154 sec.phdrs = arr_ph; 1155 sec.nphdrs = phdrs.n; 1156 sec.asns = arr_as; 1157 sec.nasns = asns.n; 1158 sec.subalign = subalign; 1159 sec.fill = fill; 1160 sec.flags = flags; 1161 sec.noload = noload; 1162 } 1163 1164 vec_free_(p, inputs.p, inputs.cap, sizeof(*inputs.p)); 1165 vec_free_(p, asns.p, asns.cap, sizeof(*asns.p)); 1166 vec_free_(p, phdrs.p, phdrs.cap, sizeof(*phdrs.p)); 1167 1168 return VEC_PUSH(p, *sections, sec); 1169 1170 fail: 1171 vec_free_(p, inputs.p, inputs.cap, sizeof(*inputs.p)); 1172 vec_free_(p, asns.p, asns.cap, sizeof(*asns.p)); 1173 vec_free_(p, phdrs.p, phdrs.cap, sizeof(*phdrs.p)); 1174 return 1; 1175 } 1176 1177 /* ---- SECTIONS{...} ---- */ 1178 1179 /* Stamp a monotonic textual-order sequence onto any top_asns / sections 1180 * pushed since the previous call. Top-level assignments and output sections 1181 * share one counter (*seq) so layout can interleave them in source order; 1182 * see KitLinkAssignment.seq / KitLinkOutputSection.seq. */ 1183 static void stamp_seq(VecAsn* top_asns, u32* prev_as, VecSec* sections, 1184 u32* prev_sec, u32* seq) { 1185 while (*prev_as < top_asns->n) top_asns->p[(*prev_as)++].seq = (*seq)++; 1186 while (*prev_sec < sections->n) sections->p[(*prev_sec)++].seq = (*seq)++; 1187 } 1188 1189 static int parse_sections_block(LSP* p, VecAsn* top_asns, VecSec* sections, 1190 VecAssert* asserts) { 1191 u32 seq = 0; 1192 u32 prev_as = 0; 1193 u32 prev_sec = 0; 1194 if (expect_ch(p, '{')) return 1; 1195 for (;;) { 1196 int ch; 1197 /* Assign source-order seq to whatever the previous iteration pushed. 1198 * (A single iteration appends at most one section but may append a 1199 * burst of assignments via parse_assignment_call.) */ 1200 stamp_seq(top_asns, &prev_as, sections, &prev_sec, &seq); 1201 skip_ws(p); 1202 if (p->err) return 1; 1203 ch = peek_ch(p); 1204 if (ch == '}') { 1205 ++p->pos; 1206 return 0; 1207 } 1208 if (ch < 0) { 1209 lsp_errf(p, p->pos, "unterminated SECTIONS block"); 1210 return 1; 1211 } 1212 /* /DISCARD/ : { body } */ 1213 if (ch == '/') { 1214 static const char kDiscard[] = "/DISCARD/"; 1215 size_t klen = sizeof(kDiscard) - 1; 1216 if (p->pos + klen <= p->len && 1217 memcmp(p->src + p->pos, kDiscard, klen) == 0) { 1218 p->pos += klen; 1219 if (parse_output_section(p, kDiscard, klen, NULL, false, sections, 1220 asserts)) 1221 return 1; 1222 continue; 1223 } 1224 lsp_errf(p, p->pos, "expected /DISCARD/ or section header"); 1225 return 1; 1226 } 1227 /* `. = expr;` at SECTIONS top level */ 1228 if (ch == '.') { 1229 size_t off = p->pos; 1230 /* Distinguish bare-dot (`. =`) from `.text :` head. Bare dot has 1231 * no id-cont following. */ 1232 if (p->pos + 1 < p->len && 1233 is_id_cont((unsigned char)p->src[p->pos + 1])) { 1234 /* falls through to identifier path */ 1235 } else { 1236 ++p->pos; 1237 skip_ws(p); 1238 if (p->err) return 1; 1239 if (!match_ch(p, '=')) { 1240 lsp_errf(p, off, "expected `. = expr`"); 1241 return 1; 1242 } 1243 { 1244 KitLinkExpr* e = parse_expr(p); 1245 KitLinkAssignment a; 1246 if (!e) return 1; 1247 (void)match_ch(p, ';'); 1248 memset(&a, 0, sizeof(a)); 1249 a.kind = KIT_LAS_DOT; 1250 a.sym = KIT_SLICE_NULL; 1251 a.expr = e; 1252 if (VEC_PUSH(p, *top_asns, a)) return 1; 1253 } 1254 continue; 1255 } 1256 } 1257 if (is_id_start(ch)) { 1258 /* either `name :` (output section) or `sym = expr;` */ 1259 const char* s; 1260 size_t n; 1261 size_t name_off; 1262 KitLinkExpr* vma = NULL; 1263 bool noload = false; 1264 if (match_kw(p, "ASSERT")) { 1265 if (parse_assertion(p, asserts)) return 1; 1266 continue; 1267 } 1268 if (match_kw(p, "PROVIDE_HIDDEN")) { 1269 if (parse_assignment_call(p, KIT_LAS_PROVIDE_HIDDEN, top_asns)) 1270 return 1; 1271 continue; 1272 } 1273 if (match_kw(p, "PROVIDE")) { 1274 if (parse_assignment_call(p, KIT_LAS_PROVIDE, top_asns)) return 1; 1275 continue; 1276 } 1277 if (match_kw(p, "HIDDEN")) { 1278 if (parse_assignment_call(p, KIT_LAS_HIDDEN, top_asns)) return 1; 1279 continue; 1280 } 1281 name_off = p->pos; 1282 if (lex_ident(p, &s, &n)) return 1; 1283 skip_ws(p); 1284 if (p->err) return 1; 1285 if (match_ch(p, '(')) { 1286 const char* ts; 1287 size_t tn; 1288 if (lex_ident(p, &ts, &tn)) return 1; 1289 if (tn == 6 && memcmp(ts, "NOLOAD", 6) == 0) 1290 noload = true; 1291 else { 1292 lsp_errf(p, name_off, "unsupported output-section type `%.*s`", 1293 (int)tn, ts); 1294 return 1; 1295 } 1296 if (expect_ch(p, ')')) return 1; 1297 skip_ws(p); 1298 if (p->err) return 1; 1299 } 1300 if (p->pos < p->len && p->src[p->pos] != ':' && 1301 p->src[p->pos] != '=') { 1302 vma = parse_expr(p); 1303 if (!vma) return 1; 1304 skip_ws(p); 1305 if (p->err) return 1; 1306 if (match_ch(p, '(')) { 1307 const char* ts; 1308 size_t tn; 1309 if (lex_ident(p, &ts, &tn)) return 1; 1310 if (tn == 6 && memcmp(ts, "NOLOAD", 6) == 0) 1311 noload = true; 1312 else { 1313 lsp_errf(p, name_off, "unsupported output-section type `%.*s`", 1314 (int)tn, ts); 1315 return 1; 1316 } 1317 if (expect_ch(p, ')')) return 1; 1318 skip_ws(p); 1319 if (p->err) return 1; 1320 } 1321 } 1322 if (p->pos < p->len && p->src[p->pos] == ':') { 1323 char* nm = lsp_strdup(p, s, n); 1324 if (!nm) return 1; 1325 if (parse_output_section(p, nm, n, vma, noload, sections, asserts)) 1326 return 1; 1327 continue; 1328 } 1329 if (match_ch(p, '=')) { 1330 KitLinkExpr* e = parse_expr(p); 1331 KitLinkAssignment a; 1332 if (!e) return 1; 1333 (void)match_ch(p, ';'); 1334 memset(&a, 0, sizeof(a)); 1335 a.kind = KIT_LAS_SYM; 1336 a.sym = lsp_slice(p, s, n); 1337 a.expr = e; 1338 if (VEC_PUSH(p, *top_asns, a)) return 1; 1339 continue; 1340 } 1341 lsp_errf(p, name_off, 1342 "expected `:` (output section) or `=` (assignment) after " 1343 "`%.*s`", 1344 (int)n, s); 1345 return 1; 1346 } 1347 lsp_errf(p, p->pos, "unexpected '%c' in SECTIONS body", (char)ch); 1348 return 1; 1349 } 1350 } 1351 1352 static int eval_const_expr(LSP* p, const KitLinkExpr* e, u64* out) { 1353 u64 a, b; 1354 if (!e) return 1; 1355 switch ((KitLinkExprKind)e->kind) { 1356 case KIT_LE_INT: 1357 *out = (u64)e->v.int_val; 1358 return 0; 1359 case KIT_LE_NEG: 1360 if (eval_const_expr(p, e->v.align.val, &a)) return 1; 1361 *out = (u64)(-(i64)a); 1362 return 0; 1363 case KIT_LE_ADD: 1364 case KIT_LE_SUB: 1365 case KIT_LE_MUL: 1366 case KIT_LE_DIV: 1367 case KIT_LE_AND: 1368 case KIT_LE_OR: 1369 case KIT_LE_XOR: 1370 case KIT_LE_SHL: 1371 case KIT_LE_SHR: 1372 case KIT_LE_MAX: 1373 case KIT_LE_MIN: 1374 if (eval_const_expr(p, e->v.bin.lhs, &a) || 1375 eval_const_expr(p, e->v.bin.rhs, &b)) 1376 return 1; 1377 switch ((KitLinkExprKind)e->kind) { 1378 case KIT_LE_ADD: 1379 *out = a + b; 1380 return 0; 1381 case KIT_LE_SUB: 1382 *out = a - b; 1383 return 0; 1384 case KIT_LE_MUL: 1385 *out = a * b; 1386 return 0; 1387 case KIT_LE_DIV: 1388 if (b == 0) { 1389 lsp_errf(p, p->pos, "division by zero in constant expression"); 1390 return 1; 1391 } 1392 *out = a / b; 1393 return 0; 1394 case KIT_LE_AND: 1395 *out = a & b; 1396 return 0; 1397 case KIT_LE_OR: 1398 *out = a | b; 1399 return 0; 1400 case KIT_LE_XOR: 1401 *out = a ^ b; 1402 return 0; 1403 case KIT_LE_SHL: 1404 *out = a << b; 1405 return 0; 1406 case KIT_LE_SHR: 1407 *out = a >> b; 1408 return 0; 1409 case KIT_LE_MAX: 1410 *out = a > b ? a : b; 1411 return 0; 1412 case KIT_LE_MIN: 1413 *out = a < b ? a : b; 1414 return 0; 1415 default: 1416 break; 1417 } 1418 break; 1419 case KIT_LE_ALIGN: 1420 case KIT_LE_BLOCK: 1421 if (eval_const_expr(p, e->v.align.val, &a) || 1422 eval_const_expr(p, e->v.align.align, &b)) 1423 return 1; 1424 *out = b ? ALIGN_UP(a, b) : a; 1425 return 0; 1426 case KIT_LE_ABSOLUTE: 1427 return eval_const_expr(p, e->v.align.val, out); 1428 default: 1429 break; 1430 } 1431 lsp_errf(p, p->pos, "non-constant expression in MEMORY region"); 1432 return 1; 1433 } 1434 1435 static int parse_memory_block(LSP* p, VecRegion* regions) { 1436 if (expect_ch(p, '{')) return 1; 1437 for (;;) { 1438 const char* ns; 1439 size_t nn; 1440 KitLinkRegion r; 1441 int have_origin = 0, have_length = 0; 1442 skip_ws(p); 1443 if (p->err) return 1; 1444 if (peek_ch(p) == '}') { 1445 ++p->pos; 1446 return 0; 1447 } 1448 if (lex_ident(p, &ns, &nn)) return 1; 1449 memset(&r, 0, sizeof(r)); 1450 r.name = lsp_slice(p, ns, nn); 1451 if (!r.name.s) return 1; 1452 skip_ws(p); 1453 if (match_ch(p, '(')) { 1454 while (!p->err && p->pos < p->len && p->src[p->pos] != ')') { 1455 char c = p->src[p->pos++]; 1456 if (c == 'r' || c == 'R') r.flags |= KIT_LRF_R; 1457 if (c == 'w' || c == 'W') r.flags |= KIT_LRF_W; 1458 if (c == 'x' || c == 'X') r.flags |= KIT_LRF_X; 1459 } 1460 if (expect_ch(p, ')')) return 1; 1461 } 1462 if (expect_ch(p, ':')) return 1; 1463 while (!p->err) { 1464 const char* ks; 1465 size_t kn; 1466 KitLinkExpr* e; 1467 u64 v; 1468 skip_ws(p); 1469 if (p->err) return 1; 1470 if (peek_ch(p) == '}') break; 1471 if (lex_ident(p, &ks, &kn)) return 1; 1472 if (expect_ch(p, '=')) return 1; 1473 e = parse_expr(p); 1474 if (!e) return 1; 1475 if (eval_const_expr(p, e, &v)) return 1; 1476 if ((kn == 6 && memcmp(ks, "ORIGIN", 6) == 0) || 1477 (kn == 3 && memcmp(ks, "org", 3) == 0) || 1478 (kn == 1 && (ks[0] == 'o' || ks[0] == 'O'))) { 1479 r.origin = v; 1480 have_origin = 1; 1481 } else if ((kn == 6 && memcmp(ks, "LENGTH", 6) == 0) || 1482 (kn == 3 && memcmp(ks, "len", 3) == 0) || 1483 (kn == 1 && (ks[0] == 'l' || ks[0] == 'L'))) { 1484 r.length = v; 1485 have_length = 1; 1486 } else { 1487 lsp_errf(p, p->pos, "unknown MEMORY field `%.*s`", (int)kn, ks); 1488 return 1; 1489 } 1490 skip_ws(p); 1491 (void)match_ch(p, ','); 1492 if (have_origin && have_length) break; 1493 } 1494 if (!have_origin || !have_length) { 1495 lsp_errf(p, p->pos, "MEMORY region `%.*s` needs ORIGIN and LENGTH", 1496 (int)nn, ns); 1497 return 1; 1498 } 1499 if (VEC_PUSH(p, *regions, r)) return 1; 1500 } 1501 } 1502 1503 static uint32_t phdr_type_from_name(const char* s, size_t n) { 1504 if (n == 7 && memcmp(s, "PT_NULL", 7) == 0) return 0u; 1505 if (n == 7 && memcmp(s, "PT_LOAD", 7) == 0) return 1u; 1506 if (n == 10 && memcmp(s, "PT_DYNAMIC", 10) == 0) return 2u; 1507 if (n == 9 && memcmp(s, "PT_INTERP", 9) == 0) return 3u; 1508 if (n == 7 && memcmp(s, "PT_NOTE", 7) == 0) return 4u; 1509 if (n == 8 && memcmp(s, "PT_SHLIB", 8) == 0) return 5u; 1510 if (n == 7 && memcmp(s, "PT_PHDR", 7) == 0) return 6u; 1511 if (n == 6 && memcmp(s, "PT_TLS", 6) == 0) return 7u; 1512 if (n == 12 && memcmp(s, "PT_GNU_STACK", 12) == 0) return 0x6474e551u; 1513 if (n == 12 && memcmp(s, "PT_GNU_RELRO", 12) == 0) return 0x6474e552u; 1514 return 1u; 1515 } 1516 1517 static int parse_phdrs_block(LSP* p, VecPhdr* phdrs) { 1518 if (expect_ch(p, '{')) return 1; 1519 for (;;) { 1520 const char *ns, *ts; 1521 size_t nn, tn; 1522 KitLinkPhdr ph; 1523 skip_ws(p); 1524 if (p->err) return 1; 1525 if (peek_ch(p) == '}') { 1526 ++p->pos; 1527 return 0; 1528 } 1529 if (lex_ident(p, &ns, &nn)) return 1; 1530 if (lex_ident(p, &ts, &tn)) return 1; 1531 memset(&ph, 0, sizeof(ph)); 1532 ph.name = lsp_slice(p, ns, nn); 1533 ph.type = phdr_type_from_name(ts, tn); 1534 if (!ph.name.s) return 1; 1535 for (;;) { 1536 skip_ws(p); 1537 if (p->err) return 1; 1538 if (match_ch(p, ';')) break; 1539 if (match_kw(p, "FILEHDR")) { 1540 ph.filehdr = true; 1541 continue; 1542 } 1543 if (match_kw(p, "PHDRS")) { 1544 ph.phdrs = true; 1545 continue; 1546 } 1547 if (match_kw(p, "FLAGS")) { 1548 if (expect_ch(p, '(')) return 1; 1549 ph.flags = parse_expr(p); 1550 if (!ph.flags) return 1; 1551 if (expect_ch(p, ')')) return 1; 1552 continue; 1553 } 1554 lsp_errf(p, p->pos, "expected PHDRS attribute or `;`"); 1555 return 1; 1556 } 1557 if (VEC_PUSH(p, *phdrs, ph)) return 1; 1558 } 1559 } 1560 1561 static int parse_extern_directive(LSP* p, VecSlice* externs) { 1562 if (expect_ch(p, '(')) return 1; 1563 for (;;) { 1564 int ch; 1565 const char* s; 1566 size_t n; 1567 KitSlice sl; 1568 skip_ws(p); 1569 if (p->err) return 1; 1570 ch = peek_ch(p); 1571 if (ch == ')') { 1572 ++p->pos; 1573 (void)match_ch(p, ';'); 1574 return 0; 1575 } 1576 if (lex_ident(p, &s, &n)) return 1; 1577 sl = lsp_slice(p, s, n); 1578 if (!sl.s) return 1; 1579 if (VEC_PUSH(p, *externs, sl)) return 1; 1580 } 1581 } 1582 1583 static int parse_output_name_directive(LSP* p, KitSlice* out) { 1584 if (expect_ch(p, '(')) return 1; 1585 if (lex_ident_or_string(p, out)) return 1; 1586 for (;;) { 1587 KitSlice ignored; 1588 skip_ws(p); 1589 if (p->err) return 1; 1590 if (match_ch(p, ')')) break; 1591 if (match_ch(p, ',')) { 1592 if (lex_ident_or_string(p, &ignored)) return 1; 1593 continue; 1594 } 1595 lsp_errf(p, p->pos, "expected `,` or `)`"); 1596 return 1; 1597 } 1598 (void)match_ch(p, ';'); 1599 return 0; 1600 } 1601 1602 /* ---- top level ---- */ 1603 1604 static int parse_top(LSP* p, KitLinkScript* out) { 1605 VecAsn top_asns = {0}; 1606 VecSec sections = {0}; 1607 VecRegion regions = {0}; 1608 VecPhdr phdrs = {0}; 1609 VecAssert asserts = {0}; 1610 VecSlice externs = {0}; 1611 KitSlice entry_name = KIT_SLICE_NULL; 1612 KitSlice output_arch = KIT_SLICE_NULL; 1613 KitSlice output_format = KIT_SLICE_NULL; 1614 int saw_sections = 0; 1615 int rc = 1; 1616 1617 for (;;) { 1618 int ch; 1619 skip_ws(p); 1620 if (p->err) goto done; 1621 if (p->pos >= p->len) break; 1622 ch = (unsigned char)p->src[p->pos]; 1623 1624 if (is_id_start(ch)) { 1625 if (match_kw(p, "ENTRY")) { 1626 const char* s; 1627 size_t n; 1628 if (expect_ch(p, '(')) goto done; 1629 if (lex_ident(p, &s, &n)) goto done; 1630 if (expect_ch(p, ')')) goto done; 1631 (void)match_ch(p, ';'); 1632 entry_name = lsp_slice(p, s, n); 1633 if (!entry_name.s) goto done; 1634 continue; 1635 } 1636 if (match_kw(p, "SECTIONS")) { 1637 if (saw_sections) { 1638 lsp_errf(p, p->pos, "duplicate SECTIONS block"); 1639 goto done; 1640 } 1641 if (parse_sections_block(p, &top_asns, §ions, &asserts)) 1642 goto done; 1643 saw_sections = 1; 1644 continue; 1645 } 1646 if (match_kw(p, "MEMORY")) { 1647 if (parse_memory_block(p, ®ions)) goto done; 1648 continue; 1649 } 1650 if (match_kw(p, "PHDRS")) { 1651 if (parse_phdrs_block(p, &phdrs)) goto done; 1652 continue; 1653 } 1654 if (match_kw(p, "EXTERN")) { 1655 if (parse_extern_directive(p, &externs)) goto done; 1656 continue; 1657 } 1658 if (match_kw(p, "ASSERT")) { 1659 if (parse_assertion(p, &asserts)) goto done; 1660 continue; 1661 } 1662 if (match_kw(p, "PROVIDE_HIDDEN")) { 1663 if (parse_assignment_call(p, KIT_LAS_PROVIDE_HIDDEN, &top_asns)) 1664 goto done; 1665 continue; 1666 } 1667 if (match_kw(p, "PROVIDE")) { 1668 if (parse_assignment_call(p, KIT_LAS_PROVIDE, &top_asns)) goto done; 1669 continue; 1670 } 1671 if (match_kw(p, "HIDDEN")) { 1672 if (parse_assignment_call(p, KIT_LAS_HIDDEN, &top_asns)) goto done; 1673 continue; 1674 } 1675 if (match_kw(p, "OUTPUT_FORMAT")) { 1676 if (parse_output_name_directive(p, &output_format)) goto done; 1677 continue; 1678 } 1679 if (match_kw(p, "OUTPUT_ARCH")) { 1680 if (parse_output_name_directive(p, &output_arch)) goto done; 1681 continue; 1682 } 1683 if (match_kw(p, "OVERLAY") || match_kw(p, "INSERT") || 1684 match_kw(p, "INPUT") || match_kw(p, "GROUP") || 1685 match_kw(p, "VERSION") || match_kw(p, "STARTUP") || 1686 match_kw(p, "SEARCH_DIR") || match_kw(p, "TARGET")) { 1687 lsp_errf(p, p->pos, 1688 "directive not supported in this linker-script subset"); 1689 goto done; 1690 } 1691 lsp_errf(p, p->pos, "unknown top-level directive"); 1692 goto done; 1693 } 1694 lsp_errf(p, p->pos, "unexpected '%c' at top level", (char)ch); 1695 goto done; 1696 } 1697 1698 /* Materialize. */ 1699 out->entry = entry_name; 1700 out->output_arch = output_arch; 1701 out->output_format = output_format; 1702 out->regions = NULL; 1703 out->nregions = 0; 1704 out->phdrs = NULL; 1705 out->nphdrs = 0; 1706 out->top_asns = NULL; 1707 out->ntop_asns = 0; 1708 out->sections = NULL; 1709 out->nsections = 0; 1710 out->asserts = NULL; 1711 out->nasserts = 0; 1712 out->externs = NULL; 1713 out->nexterns = 0; 1714 1715 if (regions.n) { 1716 KitLinkRegion* r = arena_array(p->arena, KitLinkRegion, regions.n); 1717 if (!r) goto done; 1718 memcpy(r, regions.p, sizeof(*r) * regions.n); 1719 out->regions = r; 1720 out->nregions = regions.n; 1721 } 1722 if (phdrs.n) { 1723 KitLinkPhdr* ph = arena_array(p->arena, KitLinkPhdr, phdrs.n); 1724 if (!ph) goto done; 1725 memcpy(ph, phdrs.p, sizeof(*ph) * phdrs.n); 1726 out->phdrs = ph; 1727 out->nphdrs = phdrs.n; 1728 } 1729 if (top_asns.n) { 1730 KitLinkAssignment* a = arena_array(p->arena, KitLinkAssignment, top_asns.n); 1731 if (!a) goto done; 1732 memcpy(a, top_asns.p, sizeof(*a) * top_asns.n); 1733 out->top_asns = a; 1734 out->ntop_asns = top_asns.n; 1735 } 1736 if (sections.n) { 1737 KitLinkOutputSection* s = 1738 arena_array(p->arena, KitLinkOutputSection, sections.n); 1739 if (!s) goto done; 1740 memcpy(s, sections.p, sizeof(*s) * sections.n); 1741 out->sections = s; 1742 out->nsections = sections.n; 1743 } 1744 if (asserts.n) { 1745 KitLinkAssertion* a = arena_array(p->arena, KitLinkAssertion, asserts.n); 1746 if (!a) goto done; 1747 memcpy(a, asserts.p, sizeof(*a) * asserts.n); 1748 out->asserts = a; 1749 out->nasserts = asserts.n; 1750 } 1751 if (externs.n) { 1752 KitSlice* e = arena_array(p->arena, KitSlice, externs.n); 1753 if (!e) goto done; 1754 memcpy(e, externs.p, sizeof(*e) * externs.n); 1755 out->externs = e; 1756 out->nexterns = externs.n; 1757 } 1758 rc = 0; 1759 1760 done: 1761 vec_free_(p, top_asns.p, top_asns.cap, sizeof(*top_asns.p)); 1762 vec_free_(p, sections.p, sections.cap, sizeof(*sections.p)); 1763 vec_free_(p, regions.p, regions.cap, sizeof(*regions.p)); 1764 vec_free_(p, phdrs.p, phdrs.cap, sizeof(*phdrs.p)); 1765 vec_free_(p, asserts.p, asserts.cap, sizeof(*asserts.p)); 1766 vec_free_(p, externs.p, externs.cap, sizeof(*externs.p)); 1767 return rc; 1768 } 1769 1770 /* ---- public API ---- */ 1771 1772 KitStatus kit_link_script_parse(const KitContext* ctx, KitSlice text, 1773 KitLinkScript** out) { 1774 ScriptOwner* owner; 1775 LSP p; 1776 int rc; 1777 Heap* h; 1778 1779 if (!out) return KIT_INVALID; 1780 *out = NULL; 1781 if (!ctx || !ctx->heap || !text.s) return KIT_INVALID; 1782 1783 h = ctx->heap; 1784 owner = (ScriptOwner*)h->alloc(h, sizeof(*owner), _Alignof(ScriptOwner)); 1785 if (!owner) return KIT_NOMEM; 1786 memset(owner, 0, sizeof(*owner)); 1787 /* 16 KiB blocks: matches the linker's tu arena defaults and is plenty 1788 * for the script subset we support. */ 1789 arena_init(&owner->arena, h, 16u * 1024u); 1790 1791 memset(&p, 0, sizeof(p)); 1792 p.arena = &owner->arena; 1793 p.heap = h; 1794 p.diag = ctx->diag; 1795 p.src = text.s; 1796 p.len = text.len; 1797 1798 rc = parse_top(&p, &owner->script); 1799 if (rc != 0 || p.err) { 1800 arena_fini(&owner->arena); 1801 h->free(h, owner, sizeof(*owner)); 1802 return KIT_ERR; 1803 } 1804 *out = &owner->script; 1805 return KIT_OK; 1806 } 1807 1808 void kit_link_script_free(const KitContext* ctx, KitLinkScript* s) { 1809 ScriptOwner* owner; 1810 Heap* h; 1811 if (!ctx || !ctx->heap || !s) return; 1812 owner = (ScriptOwner*)((char*)s - offsetof(ScriptOwner, script)); 1813 h = ctx->heap; 1814 arena_fini(&owner->arena); 1815 h->free(h, owner, sizeof(*owner)); 1816 }