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 {...@@ -1524,9 +1524,8 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1524 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));1524 const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
1525 defer gpa.free(data);1525 defer gpa.free(data);
15261526
1527 var script: LdScript = .{ .path = lib.path };1527 var script = try LdScript.parse(gpa, diags, lib.path, data);
1528 defer script.deinit(gpa);1528 defer script.deinit(gpa);
1529 try script.parse(data, self);
15301529
1531 var arena_allocator = std.heap.ArenaAllocator.init(gpa);1530 var arena_allocator = std.heap.ArenaAllocator.init(gpa);
1532 defer arena_allocator.deinit();1531 defer arena_allocator.deinit();
...@@ -1535,15 +1534,13 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {...@@ -1535,15 +1534,13 @@ fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
1535 var test_path = std.ArrayList(u8).init(arena);1534 var test_path = std.ArrayList(u8).init(arena);
1536 var checked_paths = std.ArrayList([]const u8).init(arena);1535 var checked_paths = std.ArrayList([]const u8).init(arena);
15371536
1538 for (script.args.items) |script_arg| {1537 for (script.args) |script_arg| {
1539 checked_paths.clearRetainingCapacity();1538 checked_paths.clearRetainingCapacity();
15401539
1541 success: {1540 success: {
1542 if (mem.startsWith(u8, script_arg.path, "-l")) {1541 if (mem.startsWith(u8, script_arg.path, "-l")) {
1543 const lib_name = script_arg.path["-l".len..];1542 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?
1547 for (self.lib_dirs) |lib_dir| {1544 for (self.lib_dirs) |lib_dir| {
1548 if (!self.base.isStatic()) {1545 if (!self.base.isStatic()) {
1549 if (try self.accessLibPath(arena, &test_path, &checked_paths, lib_dir, lib_name, .dynamic))1546 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 @@...@@ -1,14 +1,15 @@
1path: Path,1path: Path,
2cpu_arch: ?std.Target.Cpu.Arch = null,2cpu_arch: ?std.Target.Cpu.Arch,
3args: std.ArrayListUnmanaged(Arg) = .empty,3args: []const Arg,
44
5pub const Arg = struct {5pub const Arg = struct {
6 needed: bool = false,6 needed: bool = false,
7 path: []const u8,7 path: []const u8,
8};8};
99
10pub fn deinit(scr: *LdScript, allocator: Allocator) void {10pub fn deinit(ls: *LdScript, gpa: Allocator) void {
11 scr.args.deinit(allocator);11 gpa.free(ls.args);
12 ls.* = undefined;
12}13}
1314
14pub const Error = error{15pub const Error = error{
...@@ -18,28 +19,30 @@ pub const Error = error{...@@ -18,28 +19,30 @@ pub const Error = error{
18 OutOfMemory,19 OutOfMemory,
19};20};
2021
21pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {22pub fn parse(
22 const comp = elf_file.base.comp;23 gpa: Allocator,
23 const gpa = comp.gpa;24 diags: *Diags,
24 const diags = &comp.link_diags;25 /// For error reporting.
2526 path: Path,
27 data: []const u8,
28) Error!LdScript {
26 var tokenizer = Tokenizer{ .source = data };29 var tokenizer = Tokenizer{ .source = data };
27 var tokens = std.ArrayList(Token).init(gpa);30 var tokens: std.ArrayListUnmanaged(Token) = .empty;
28 defer tokens.deinit();31 defer tokens.deinit(gpa);
29 var line_col = std.ArrayList(LineColumn).init(gpa);32 var line_col: std.ArrayListUnmanaged(LineColumn) = .empty;
30 defer line_col.deinit();33 defer line_col.deinit(gpa);
3134
32 var line: usize = 0;35 var line: usize = 0;
33 var prev_line_last_col: usize = 0;36 var prev_line_last_col: usize = 0;
3437
35 while (true) {38 while (true) {
36 const tok = tokenizer.next();39 const tok = tokenizer.next();
37 try tokens.append(tok);40 try tokens.append(gpa, tok);
38 const column = tok.start - prev_line_last_col;41 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 });
40 switch (tok.id) {43 switch (tok.id) {
41 .invalid => {44 .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})", .{
43 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,46 std.fmt.fmtSliceEscapeLower(tok.get(data)), line, column,
44 });47 });
45 },48 },
...@@ -52,18 +55,22 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -52,18 +55,22 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
52 }55 }
53 }56 }
5457
55 var it = TokenIterator{ .tokens = tokens.items };58 var it: TokenIterator = .{ .tokens = tokens.items };
56 var parser = Parser{ .source = data, .it = &it };59 var parser: Parser = .{
57 var args = std.ArrayList(Arg).init(gpa);60 .gpa = gpa,
58 scr.doParse(.{61 .source = data,
59 .parser = &parser,62 .it = &it,
60 .args = &args,63 .args = .empty,
61 }) catch |err| switch (err) {64 .cpu_arch = null,
65 };
66 defer parser.args.deinit(gpa);
67
68 parser.start() catch |err| switch (err) {
62 error.UnexpectedToken => {69 error.UnexpectedToken => {
63 const last_token_id = parser.it.pos - 1;70 const last_token_id = parser.it.pos - 1;
64 const last_token = parser.it.get(last_token_id);71 const last_token = parser.it.get(last_token_id);
65 const lcol = line_col.items[last_token_id];72 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})", .{
67 @tagName(last_token.id),74 @tagName(last_token.id),
68 last_token.get(data),75 last_token.get(data),
69 lcol.line,76 lcol.line,
...@@ -72,30 +79,10 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {...@@ -72,30 +79,10 @@ pub fn parse(scr: *LdScript, data: []const u8, elf_file: *Elf) Error!void {
72 },79 },
73 else => |e| return e,80 else => |e| return e,
74 };81 };
75 scr.args = args.moveToUnmanaged();82 return .{
76}83 .path = path,
7784 .cpu_arch = parser.cpu_arch,
78fn doParse(scr: *LdScript, ctx: struct {85 .args = try parser.args.toOwnedSlice(gpa),
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,
99 };86 };
100}87}
10188
...@@ -126,9 +113,34 @@ const Command = enum {...@@ -126,9 +113,34 @@ const Command = enum {
126};113};
127114
128const Parser = struct {115const Parser = struct {
116 gpa: Allocator,
129 source: []const u8,117 source: []const u8,
130 it: *TokenIterator,118 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
132 fn outputFormat(p: *Parser) !std.Target.Cpu.Arch {144 fn outputFormat(p: *Parser) !std.Target.Cpu.Arch {
133 const value = value: {145 const value = value: {
134 if (p.skip(&.{.lparen})) {146 if (p.skip(&.{.lparen})) {
...@@ -149,18 +161,19 @@ const Parser = struct {...@@ -149,18 +161,19 @@ const Parser = struct {
149 return error.UnknownCpuArch;161 return error.UnknownCpuArch;
150 }162 }
151163
152 fn group(p: *Parser, args: *std.ArrayList(Arg)) !void {164 fn group(p: *Parser) !void {
165 const gpa = p.gpa;
153 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;166 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
154167
155 while (true) {168 while (true) {
156 if (p.maybe(.literal)) |tok_id| {169 if (p.maybe(.literal)) |tok_id| {
157 const tok = p.it.get(tok_id);170 const tok = p.it.get(tok_id);
158 const path = tok.get(p.source);171 const path = tok.get(p.source);
159 try args.append(.{ .path = path, .needed = true });172 try p.args.append(gpa, .{ .path = path, .needed = true });
160 } else if (p.maybe(.command)) |cmd_id| {173 } else if (p.maybe(.command)) |cmd_id| {
161 const cmd = p.getCommand(cmd_id);174 const cmd = p.getCommand(cmd_id);
162 switch (cmd) {175 switch (cmd) {
163 .as_needed => try p.asNeeded(args),176 .as_needed => try p.asNeeded(),
164 else => return error.UnexpectedToken,177 else => return error.UnexpectedToken,
165 }178 }
166 } else break;179 } else break;
...@@ -169,13 +182,14 @@ const Parser = struct {...@@ -169,13 +182,14 @@ const Parser = struct {
169 _ = try p.require(.rparen);182 _ = try p.require(.rparen);
170 }183 }
171184
172 fn asNeeded(p: *Parser, args: *std.ArrayList(Arg)) !void {185 fn asNeeded(p: *Parser) !void {
186 const gpa = p.gpa;
173 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;187 if (!p.skip(&.{.lparen})) return error.UnexpectedToken;
174188
175 while (p.maybe(.literal)) |tok_id| {189 while (p.maybe(.literal)) |tok_id| {
176 const tok = p.it.get(tok_id);190 const tok = p.it.get(tok_id);
177 const path = tok.get(p.source);191 const path = tok.get(p.source);
178 try args.append(.{ .path = path, .needed = false });192 try p.args.append(gpa, .{ .path = path, .needed = false });
179 }193 }
180194
181 _ = try p.require(.rparen);195 _ = try p.require(.rparen);
...@@ -227,21 +241,19 @@ const Token = struct {...@@ -227,21 +241,19 @@ const Token = struct {
227 end: usize,241 end: usize,
228242
229 const Id = enum {243 const Id = enum {
230 // zig fmt: off
231 eof,244 eof,
232 invalid,245 invalid,
233246
234 new_line,247 new_line,
235 lparen, // (248 lparen, // (
236 rparen, // )249 rparen, // )
237 lbrace, // {250 lbrace, // {
238 rbrace, // }251 rbrace, // }
239252
240 comment, // /* */253 comment, // /* */
241254
242 command, // literal with special meaning, see Command255 command, // literal with special meaning, see Command
243 literal,256 literal,
244 // zig fmt: on
245 };257 };
246258
247 const Index = usize;259 const Index = usize;
...@@ -430,10 +442,9 @@ const TokenIterator = struct {...@@ -430,10 +442,9 @@ const TokenIterator = struct {
430};442};
431443
432const LdScript = @This();444const LdScript = @This();
445const Diags = @import("../../link.zig").Diags;
433446
434const std = @import("std");447const std = @import("std");
435const assert = std.debug.assert;448const assert = std.debug.assert;
436const Path = std.Build.Cache.Path;449const Path = std.Build.Cache.Path;
437
438const Allocator = std.mem.Allocator;450const Allocator = std.mem.Allocator;
439const Elf = @import("../Elf.zig");