authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-14 15:24:13-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-10-23 16:27:38-07:00
log028a9a10549e59e84105515ffb50c491f487c91a
treeee429c3d7682d76d472f11beecfc14d28e7b9d64
parent33d07f4b6efe461ee3fbfa32cb18f60aac8c2827

link.Elf.LdScript: eliminate dependency on Elf.File

this allows it to be used by the frontend

2 files changed, 76 insertions(+), 68 deletions(-)

src/link/Elf.zig+2-5
......@@ -1524,9 +1524,8 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
15241524 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
15251525 defer gpa.free(data);
15261526
1527 var script: LdScript = .{ .path = lib.path };
1527 var script = try LdScript.parse(gpa, diags, lib.path, data);
15281528 defer script.deinit(gpa);
1529 try script.parse(data, self);
15301529
15311530 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
15321531 defer arena_allocator.deinit();
......@@ -1535,15 +1534,13 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
15351534 var test_path = std.ArrayList(u8).init(arena);
15361535 var checked_paths = std.ArrayList([]const u8).init(arena);
15371536
1538 for (script.args.items) |script_arg| {
1537 for (script.args) |script_arg| {
15391538 checked_paths.clearRetainingCapacity();
15401539
15411540 success: {
15421541 if (mem.startsWith(u8, script_arg.path, "-l")) {
15431542 const lib_name = script_arg.path["-l".len..];
15441543
1545 // TODO I think technically we should re-use the mechanism used by the frontend here.
1546 // Maybe we should hoist search-strategy all the way here?
15471544 for (self.lib_dirs) |lib_dir| {
15481545 if (!self.base.isStatic()) {
15491546 if (try self.accessLibPath(arena, &test_path, &checked_paths, lib_dir, lib_name, .dynamic))
src/link/Elf/LdScript.zig+74-63
......@@ -1,14 +1,15 @@
11path: Path,
2cpu_arch: ?std.Target.Cpu.Arch = null,
3args: std.ArrayListUnmanaged(Arg) = .empty,
2cpu_arch: ?std.Target.Cpu.Arch,
3args: []const Arg,
44
55pub const Arg = struct {
66 needed: bool = false,
77 path: []const u8,
88};
99
10pub fn deinit(scr: *LdScript, allocator: Allocator) void {
11 scr.args.deinit(allocator);
10pub fn deinit(ls: *LdScript, gpa: Allocator) void {
11 gpa.free(ls.args);
12 ls.* = undefined;
1213}
1314
1415pub const Error = error{
......@@ -18,28 +19,30 @@ pub const Error = error{
1819 OutOfMemory,
1920};
2021
21pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
22 const comp = elf_file.base.comp;
23 const gpa = comp.gpa;
24 const diags = &comp.link_diags;
25
22pub fn parse(
23 gpa: Allocator,
24 diags: *Diags,
25 /// For error reporting.
26 path: Path,
27 data: []const u8,
28) Error!LdScript {
2629 var tokenizer = Tokenizer{ .source = data };
27 var tokens = std.ArrayList(Token).init(gpa);
28 defer tokens.deinit();
29 var line_col = std.ArrayList(LineColumn).init(gpa);
30 defer line_col.deinit();
30 var tokens: std.ArrayListUnmanaged(Token) = .empty;
31 defer tokens.deinit(gpa);
32 var line_col: std.ArrayListUnmanaged(LineColumn) = .empty;
33 defer line_col.deinit(gpa);
3134
3235 var line: usize = 0;
3336 var prev_line_last_col: usize = 0;
3437
3538 while (true) {
3639 const tok = tokenizer.next();
37 try tokens.append(tok);
40 try tokens.append(gpa, tok);
3841 const column = tok.start - prev_line_last_col;
39 try line_col.append(.{ .line = line, .column = column });
42 try line_col.append(gpa, .{ .line = line, .column = column });
4043 switch (tok.id) {
4144 .invalid => {
42 return diags.failParse(scr.path, "invalid token in LD script: '{s}' ({d}:{d})", .{
45 return diags.failParse(path, "invalid token in LD script: '{s}' ({d}:{d})", .{
4346 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,
4447 });
4548 },
......@@ -52,18 +55,22 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
5255 }
5356 }
5457
55 var it = TokenIterator{ .tokens = tokens.items };
56 var parser = Parser{ .source = data, .it = &it };
57 var args = std.ArrayList(Arg).init(gpa);
58 scr.doParse(.{
59 .parser = &parser,
60 .args = &args,
61 }) catch |err| switch (err) {
58 var it: TokenIterator = .{ .tokens = tokens.items };
59 var parser: Parser = .{
60 .gpa = gpa,
61 .source = data,
62 .it = &it,
63 .args = .empty,
64 .cpu_arch = null,
65 };
66 defer parser.args.deinit(gpa);
67
68 parser.start() catch |err| switch (err) {
6269 error.UnexpectedToken => {
6370 const last_token_id = parser.it.pos - 1;
6471 const last_token = parser.it.get(last_token_id);
6572 const lcol = line_col.items[last_token_id];
66 return diags.failParse(scr.path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{
73 return diags.failParse(path, "unexpected token in LD script: {s}: '{s}' ({d}:{d})", .{
6774 @tagName(last_token.id),
6875 last_token.get(data),
6976 lcol.line,
......@@ -72,30 +79,10 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
7279 },
7380 else => |e| return e,
7481 };
75 scr.args = args.moveToUnmanaged();
76}
77
78fn doParse(scr: *LdScript, ctx: struct {
79 parser: *Parser,
80 args: *std.ArrayList(Arg),
81}) !void {
82 while (true) {
83 ctx.parser.skipAny(&.{ .comment, .new_line });
84
85 if (ctx.parser.maybe(.command)) |cmd_id| {
86 const cmd = ctx.parser.getCommand(cmd_id);
87 switch (cmd) {
88 .output_format => scr.cpu_arch = try ctx.parser.outputFormat(),
89 // TODO we should verify that group only contains libraries
90 .input, .group => try ctx.parser.group(ctx.args),
91 else => return error.UnexpectedToken,
92 }
93 } else break;
94 }
95
96 if (ctx.parser.it.next()) |tok| switch (tok.id) {
97 .eof => {},
98 else => return error.UnexpectedToken,
82 return .{
83 .path = path,
84 .cpu_arch = parser.cpu_arch,
85 .args = try parser.args.toOwnedSlice(gpa),
9986 };
10087}
10188
......@@ -126,9 +113,34 @@ const Command = enum {
126113};
127114
128115const Parser = struct {
116 gpa: Allocator,
129117 source: []const u8,
130118 it: *TokenIterator,
131119
120 cpu_arch: ?std.Target.Cpu.Arch,
121 args: std.ArrayListUnmanaged(Arg),
122
123 fn start(parser: *Parser) !void {
124 while (true) {
125 parser.skipAny(&.{ .comment, .new_line });
126
127 if (parser.maybe(.command)) |cmd_id| {
128 const cmd = parser.getCommand(cmd_id);
129 switch (cmd) {
130 .output_format => parser.cpu_arch = try parser.outputFormat(),
131 // TODO we should verify that group only contains libraries
132 .input, .group => try parser.group(),
133 else => return error.UnexpectedToken,
134 }
135 } else break;
136 }
137
138 if (parser.it.next()) |tok| switch (tok.id) {
139 .eof => {},
140 else => return error.UnexpectedToken,
141 };
142 }
143
132144 fn outputFormat(p: *Parser) !std.Target.Cpu.Arch {
133145 const value = value: {
134146 if (p.skip(&.{.lparen})) {
......@@ -149,18 +161,19 @@ const Parser = struct {
149161 return error.UnknownCpuArch;
150162 }
151163
152 fn group(p: *Parser, args: *std.ArrayList(Arg)) !void {
164 fn group(p: *Parser) !void {
165 const gpa = p.gpa;
153166 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
154167
155168 while (true) {
156169 if (p.maybe(.literal)) |tok_id| {
157170 const tok = p.it.get(tok_id);
158171 const path = tok.get(p.source);
159 try args.append(.{ .path = path, .needed = true });
172 try p.args.append(gpa, .{ .path = path, .needed = true });
160173 } else if (p.maybe(.command)) |cmd_id| {
161174 const cmd = p.getCommand(cmd_id);
162175 switch (cmd) {
163 .as_needed => try p.asNeeded(args),
176 .as_needed => try p.asNeeded(),
164177 else => return error.UnexpectedToken,
165178 }
166179 } else break;
......@@ -169,13 +182,14 @@ const Parser = struct {
169182 _ = try p.require(.rparen);
170183 }
171184
172 fn asNeeded(p: *Parser, args: *std.ArrayList(Arg)) !void {
185 fn asNeeded(p: *Parser) !void {
186 const gpa = p.gpa;
173187 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
174188
175189 while (p.maybe(.literal)) |tok_id| {
176190 const tok = p.it.get(tok_id);
177191 const path = tok.get(p.source);
178 try args.append(.{ .path = path, .needed = false });
192 try p.args.append(gpa, .{ .path = path, .needed = false });
179193 }
180194
181195 _ = try p.require(.rparen);
......@@ -227,21 +241,19 @@ const Token = struct {
227241 end: usize,
228242
229243 const Id = enum {
230 // zig fmt: off
231244 eof,
232245 invalid,
233246
234247 new_line,
235 lparen, // (
236 rparen, // )
237 lbrace, // {
238 rbrace, // }
248 lparen, // (
249 rparen, // )
250 lbrace, // {
251 rbrace, // }
239252
240 comment, // /* */
253 comment, // /* */
241254
242 command, // literal with special meaning, see Command
255 command, // literal with special meaning, see Command
243256 literal,
244 // zig fmt: on
245257 };
246258
247259 const Index = usize;
......@@ -430,10 +442,9 @@ const TokenIterator = struct {
430442};
431443
432444const LdScript = @This();
445const Diags = @import("../../link.zig").Diags;
433446
434447const std = @import("std");
435448const assert = std.debug.assert;
436449const Path = std.Build.Cache.Path;
437
438450const Allocator = std.mem.Allocator;
439const Elf = @import("../Elf.zig");