authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-08 23:45:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-08 23:45:25-07:00
log04d44db6cc764c1fceca27fe8f0d3651142ba5f3
tree4f4cd6a5b0ef012ce9c8b5f5281dcd92268d6195
parent808b9239a3f5d32ffb5207ce48ef417e56a80720

tools/gen_stubs: consolidate symbol properties into MultiSym


1 files changed, 212 insertions(+), 81 deletions(-)

tools/gen_stubs.zig+212-81
...@@ -6,51 +6,143 @@...@@ -6,51 +6,143 @@
6//!6//!
7//! ...each with 'lib/libc.so' inside of them.7//! ...each with 'lib/libc.so' inside of them.
88
9// TODO: pick the best index to put them into instead of at the end
10// - e.g. find a common previous symbol and put it after that one
11// - they definitely need to go into the correct section
12// TODO: emit MultiSyms to use the preprocessor
13
9const std = @import("std");14const std = @import("std");
10const builtin = std.builtin;15const builtin = std.builtin;
11const mem = std.mem;16const mem = std.mem;
17const log = std.log;
12const elf = std.elf;18const elf = std.elf;
13const native_endian = @import("builtin").target.cpu.arch.endian();19const native_endian = @import("builtin").target.cpu.arch.endian();
1420
21const arches: [6]std.Target.Cpu.Arch = blk: {
22 var result: [6]std.Target.Cpu.Arch = undefined;
23 for (.{ .riscv64, .mips, .i386, .x86_64, .powerpc, .powerpc64 }) |arch| {
24 result[archIndex(arch)] = arch;
25 }
26 break :blk result;
27};
28
29const MultiSym = struct {
30 size: [arches.len]u64,
31 present: [arches.len]bool,
32 section: u16,
33 ty: u4,
34 binding: u4,
35 visib: elf.STV,
36};
37
38const Parse = struct {
39 arena: mem.Allocator,
40 sym_table: *std.StringArrayHashMap(MultiSym),
41 sections: *std.StringArrayHashMap(void),
42 elf_bytes: []align(@alignOf(elf.Elf64_Ehdr)) u8,
43 header: elf.Header,
44 arch: std.Target.Cpu.Arch,
45};
46
15pub fn main() !void {47pub fn main() !void {
16 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);48 var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
17 defer arena_instance.deinit();49 defer arena_instance.deinit();
18 const arena = arena_instance.allocator();50 const arena = arena_instance.allocator();
1951
20 const args = try std.process.argsAlloc(arena);52 const args = try std.process.argsAlloc(arena);
21 const libc_so_path = args[1];53 const build_all_path = args[1];
2254
23 // Read the ELF header.55 var build_all_dir = try std.fs.cwd().openDir(build_all_path, .{});
24 const elf_bytes = try std.fs.cwd().readFileAllocOptions(56
25 arena,57 for (arches) |arch| {
26 libc_so_path,58 const libc_so_path = try std.fmt.allocPrint(arena, "{s}/lib/libc.so", .{@tagName(arch)});
27 100 * 1024 * 1024,59
28 1 * 1024 * 1024,60 // Read the ELF header.
29 @alignOf(elf.Elf64_Ehdr),61 const elf_bytes = try build_all_dir.readFileAllocOptions(
30 null,62 arena,
31 );63 libc_so_path,
32 const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]);64 100 * 1024 * 1024,
3365 1 * 1024 * 1024,
34 switch (header.is_64) {66 @alignOf(elf.Elf64_Ehdr),
35 true => switch (header.endian) {67 null,
36 .Big => return finishMain(arena, elf_bytes, header, true, .Big),68 );
37 .Little => return finishMain(arena, elf_bytes, header, true, .Little),69 const header = try elf.Header.parse(elf_bytes[0..@sizeOf(elf.Elf64_Ehdr)]);
38 },70
39 false => switch (header.endian) {71 var sym_table = std.StringArrayHashMap(MultiSym).init(arena);
40 .Big => return finishMain(arena, elf_bytes, header, false, .Big),72 var sections = std.StringArrayHashMap(void).init(arena);
41 .Little => return finishMain(arena, elf_bytes, header, false, .Little),73
42 },74 const parse: Parse = .{
75 .arena = arena,
76 .sym_table = &sym_table,
77 .sections = &sections,
78 .elf_bytes = elf_bytes,
79 .header = header,
80 .arch = arch,
81 };
82
83 switch (header.is_64) {
84 true => switch (header.endian) {
85 .Big => try parseElf(parse, true, .Big),
86 .Little => try parseElf(parse, true, .Little),
87 },
88 false => switch (header.endian) {
89 .Big => try parseElf(parse, false, .Big),
90 .Little => try parseElf(parse, false, .Little),
91 },
92 }
43 }93 }
94
95 const stdout = std.io.getStdOut().writer();
96 _ = stdout;
97
98 //var prev_section: u16 = 0;
99 //for (all_syms) |sym| {
100 // const this_section = s(sym.st_shndx);
101 // if (this_section != prev_section) {
102 // prev_section = this_section;
103 // const sh_name = mem.sliceTo(shstrtab[s(shdrs[this_section].sh_name)..], 0);
104 // try stdout.print("{s}\n", .{sh_name});
105 // }
106
107 // switch (binding) {
108 // elf.STB_GLOBAL => {
109 // try stdout.print(".globl {s}\n", .{name});
110 // },
111 // elf.STB_WEAK => {
112 // try stdout.print(".weak {s}\n", .{name});
113 // },
114 // else => unreachable,
115 // }
116
117 // switch (ty) {
118 // elf.STT_NOTYPE => {},
119 // elf.STT_FUNC => {
120 // try stdout.print(".type {s}, %function;\n", .{name});
121 // // omitting the size is OK for functions
122 // },
123 // elf.STT_OBJECT => {
124 // try stdout.print(".type {s}, %object;\n", .{name});
125 // if (size != 0) {
126 // try stdout.print(".size {s}, {d}\n", .{ name, size });
127 // }
128 // },
129 // else => unreachable,
130 // }
131
132 // switch (visib) {
133 // .DEFAULT => {},
134 // .PROTECTED => try stdout.print(".protected {s}\n", .{name}),
135 // .INTERNAL, .HIDDEN => unreachable,
136 // }
137
138 // try stdout.print("{s}:\n", .{name});
139 //}
44}140}
45141
46fn finishMain(142fn parseElf(parse: Parse, comptime is_64: bool, comptime endian: builtin.Endian) !void {
47 arena: mem.Allocator,143 const arena = parse.arena;
48 elf_bytes: []align(@alignOf(elf.Elf64_Ehdr)) u8,144 const elf_bytes = parse.elf_bytes;
49 header: elf.Header,145 const header = parse.header;
50 comptime is_64: bool,
51 comptime endian: builtin.Endian,
52) !void {
53 _ = arena;
54 const Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym;146 const Sym = if (is_64) elf.Elf64_Sym else elf.Elf32_Sym;
55 const S = struct {147 const S = struct {
56 fn endianSwap(x: anytype) @TypeOf(x) {148 fn endianSwap(x: anytype) @TypeOf(x) {
...@@ -73,17 +165,26 @@ fn finishMain(...@@ -73,17 +165,26 @@ fn finishMain(
73165
74 // Obtain the section header string table.166 // Obtain the section header string table.
75 const shstrtab_offset = s(shdrs[header.shstrndx].sh_offset);167 const shstrtab_offset = s(shdrs[header.shstrndx].sh_offset);
76 std.log.debug("shstrtab is at offset {d}", .{shstrtab_offset});168 log.debug("shstrtab is at offset {d}", .{shstrtab_offset});
77 const shstrtab = elf_bytes[shstrtab_offset..];169 const shstrtab = elf_bytes[shstrtab_offset..];
78170
171 // Maps this ELF file's section header index to the multi arch section ArrayHashMap index.
172 const section_index_map = try arena.alloc(u16, shdrs.len);
173
79 // Find the offset of the dynamic symbol table.174 // Find the offset of the dynamic symbol table.
80 const dynsym_index = for (shdrs) |shdr, i| {175 var dynsym_index: u16 = 0;
81 const sh_name = mem.sliceTo(shstrtab[s(shdr.sh_name)..], 0);176 for (shdrs) |shdr, i| {
82 std.log.debug("found section: {s}", .{sh_name});177 const sh_name = try arena.dupe(u8, mem.sliceTo(shstrtab[s(shdr.sh_name)..], 0));
83 if (mem.eql(u8, sh_name, ".dynsym")) break @intCast(u16, i);178 log.debug("found section: {s}", .{sh_name});
84 } else @panic("did not find the .dynsym section");179 if (mem.eql(u8, sh_name, ".dynsym")) {
180 dynsym_index = @intCast(u16, i);
181 }
182 const gop = try parse.sections.getOrPut(sh_name);
183 section_index_map[i] = @intCast(u16, gop.index);
184 }
185 if (dynsym_index == 0) @panic("did not find the .dynsym section");
85186
86 std.log.debug("found .dynsym section at index {d}", .{dynsym_index});187 log.debug("found .dynsym section at index {d}", .{dynsym_index});
87188
88 // Read the dynamic symbols into a list.189 // Read the dynamic symbols into a list.
89 const dyn_syms_off = s(shdrs[dynsym_index].sh_offset);190 const dyn_syms_off = s(shdrs[dynsym_index].sh_offset);
...@@ -96,25 +197,25 @@ fn finishMain(...@@ -96,25 +197,25 @@ fn finishMain(
96 // Sort the list by address, ascending.197 // Sort the list by address, ascending.
97 std.sort.sort(Sym, dyn_syms, {}, S.symbolAddrLessThan);198 std.sort.sort(Sym, dyn_syms, {}, S.symbolAddrLessThan);
98199
99 const stdout = std.io.getStdOut().writer();
100
101 var prev_section: u16 = 0;
102 for (dyn_syms) |sym| {200 for (dyn_syms) |sym| {
103 const name = mem.sliceTo(dynstr[s(sym.st_name)..], 0);201 const this_section = s(sym.st_shndx);
202 const name = try arena.dupe(u8, mem.sliceTo(dynstr[s(sym.st_name)..], 0));
104 const ty = @truncate(u4, sym.st_info);203 const ty = @truncate(u4, sym.st_info);
105 const binding = @truncate(u4, sym.st_info >> 4);204 const binding = @truncate(u4, sym.st_info >> 4);
106 const visib = @intToEnum(elf.STV, @truncate(u2, sym.st_other));205 const visib = @intToEnum(elf.STV, @truncate(u2, sym.st_other));
107 const size = s(sym.st_size);206 const size = s(sym.st_size);
108207
109 if (size == 0) {208 if (size == 0) {
110 std.log.warn("symbol '{s}' has size 0", .{name});209 log.warn("{s}: symbol '{s}' has size 0", .{ @tagName(parse.arch), name });
111 continue;210 continue;
112 }211 }
113212
114 switch (binding) {213 switch (binding) {
115 elf.STB_GLOBAL, elf.STB_WEAK => {},214 elf.STB_GLOBAL, elf.STB_WEAK => {},
116 else => {215 else => {
117 std.log.debug("skipping '{s}' due to it having binding '{d}'", .{ name, binding });216 log.debug("{s}: skipping '{s}' due to it having binding '{d}'", .{
217 @tagName(parse.arch), name, binding,
218 });
118 continue;219 continue;
119 },220 },
120 }221 }
...@@ -122,7 +223,9 @@ fn finishMain(...@@ -122,7 +223,9 @@ fn finishMain(
122 switch (ty) {223 switch (ty) {
123 elf.STT_NOTYPE, elf.STT_FUNC, elf.STT_OBJECT => {},224 elf.STT_NOTYPE, elf.STT_FUNC, elf.STT_OBJECT => {},
124 else => {225 else => {
125 std.log.debug("skipping '{s}' due to it having type '{d}'", .{ name, ty });226 log.debug("{s}: skipping '{s}' due to it having type '{d}'", .{
227 @tagName(parse.arch), name, ty,
228 });
126 continue;229 continue;
127 },230 },
128 }231 }
...@@ -130,51 +233,79 @@ fn finishMain(...@@ -130,51 +233,79 @@ fn finishMain(
130 switch (visib) {233 switch (visib) {
131 .DEFAULT, .PROTECTED => {},234 .DEFAULT, .PROTECTED => {},
132 .INTERNAL, .HIDDEN => {235 .INTERNAL, .HIDDEN => {
133 std.log.debug("skipping '{s}' due to it having visibility '{s}'", .{236 log.debug("{s}: skipping '{s}' due to it having visibility '{s}'", .{
134 name, @tagName(visib),237 @tagName(parse.arch), name, @tagName(visib),
135 });238 });
136 continue;239 continue;
137 },240 },
138 }241 }
139242
140 const this_section = s(sym.st_shndx);243 const gop = try parse.sym_table.getOrPut(name);
141 if (this_section != prev_section) {244 if (gop.found_existing) {
142 prev_section = this_section;245 if (gop.value_ptr.section != section_index_map[this_section]) {
143 const sh_name = mem.sliceTo(shstrtab[s(shdrs[this_section].sh_name)..], 0);246 const sh_name = mem.sliceTo(shstrtab[s(shdrs[this_section].sh_name)..], 0);
144 try stdout.print("{s}\n", .{sh_name});247 fatal("symbol '{s}' in arch {s} is in section {s} but in arch {s} is in section {s}", .{
145 }248 name, @tagName(parse.arch), sh_name,
146249 archSetName(gop.value_ptr.present), parse.sections.keys()[gop.value_ptr.section],
147 switch (binding) {250 });
148 elf.STB_GLOBAL => {251 }
149 try stdout.print(".globl {s}\n", .{name});252 if (gop.value_ptr.ty != ty) {
150 },253 fatal("symbol '{s}' in arch {s} has type {d} but in arch {s} has type {d}", .{
151 elf.STB_WEAK => {254 name, @tagName(parse.arch), ty,
152 try stdout.print(".weak {s}\n", .{name});255 archSetName(gop.value_ptr.present), gop.value_ptr.ty,
153 },256 });
154 else => unreachable,257 }
258 if (gop.value_ptr.binding != binding) {
259 fatal("symbol '{s}' in arch {s} has binding {d} but in arch {s} has binding {d}", .{
260 name, @tagName(parse.arch), binding,
261 archSetName(gop.value_ptr.present), gop.value_ptr.binding,
262 });
263 }
264 if (gop.value_ptr.visib != visib) {
265 fatal("symbol '{s}' in arch {s} has visib {s} but in arch {s} has visib {s}", .{
266 name, @tagName(parse.arch), @tagName(visib),
267 archSetName(gop.value_ptr.present), @tagName(gop.value_ptr.visib),
268 });
269 }
270 } else {
271 gop.value_ptr.* = .{
272 .present = [1]bool{false} ** arches.len,
273 .section = section_index_map[this_section],
274 .ty = ty,
275 .binding = binding,
276 .visib = visib,
277 .size = [1]u64{0} ** arches.len,
278 };
155 }279 }
280 gop.value_ptr.present[archIndex(parse.arch)] = true;
281 gop.value_ptr.size[archIndex(parse.arch)] = size;
282 }
283}
156284
157 switch (ty) {285fn archIndex(arch: std.Target.Cpu.Arch) u8 {
158 elf.STT_NOTYPE => {},286 return switch (arch) {
159 elf.STT_FUNC => {287 // zig fmt: off
160 try stdout.print(".type {s}, %function;\n", .{name});288 .riscv64 => 0,
161 // omitting the size is OK for functions289 .mips => 1,
162 },290 .i386 => 2,
163 elf.STT_OBJECT => {291 .x86_64 => 3,
164 try stdout.print(".type {s}, %object;\n", .{name});292 .powerpc => 4,
165 if (size != 0) {293 .powerpc64 => 5,
166 try stdout.print(".size {s}, {d}\n", .{ name, size });294 else => unreachable,
167 }295 // zig fmt: on
168 },296 };
169 else => unreachable,297}
170 }
171298
172 switch (visib) {299fn archSetName(arch_set: [arches.len]bool) []const u8 {
173 .DEFAULT => {},300 for (arches) |arch, i| {
174 .PROTECTED => try stdout.print(".protected {s}\n", .{name}),301 if (arch_set[i]) {
175 .INTERNAL, .HIDDEN => unreachable,302 return @tagName(arch);
176 }303 }
177
178 try stdout.print("{s}:\n", .{name});
179 }304 }
305 return "(none)";
306}
307
308fn fatal(comptime format: []const u8, args: anytype) noreturn {
309 log.err(format, args);
310 std.process.exit(1);
180}311}