authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-14 16:34:04-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-14 16:34:04-04:00
log81a01bd4815779ebeb5898a825bf91628b75ff47
tree01ee2cdca6ba698915667b17cd4dc52735eece02
parent0986dcf1cf5b67ad2b2e606622bf9b2c22e01194

fix codegen of sentinel-terminated arrays and .got alignment

we now have an exit(0) program working

5 files changed, 275 insertions(+), 107 deletions(-)

lib/std/mem.zig+5-1
......@@ -2099,7 +2099,11 @@ pub fn alignBackwardGeneric(comptime T: type, addr: T, alignment: T) T {
20992099/// Given an address and an alignment, return true if the address is a multiple of the alignment
21002100/// The alignment must be a power of 2 and greater than 0.
21012101pub fn isAligned(addr: usize, alignment: usize) bool {
2102 return alignBackward(addr, alignment) == addr;
2102 return isAlignedGeneric(u64, addr, alignment);
2103}
2104
2105pub fn isAlignedGeneric(comptime T: type, addr: T, alignment: T) bool {
2106 return alignBackwardGeneric(T, addr, alignment) == addr;
21032107}
21042108
21052109test "isAligned" {
src-self-hosted/codegen.zig+47-7
......@@ -10,8 +10,10 @@ const Target = std.Target;
1010const Allocator = mem.Allocator;
1111
1212pub const Result = union(enum) {
13 /// This value might or might not alias the `code` parameter passed to `generateSymbol`.
14 ok: []const u8,
13 /// The `code` parameter passed to `generateSymbol` has the value appended.
14 appended: void,
15 /// The value is available externally, `code` is unused.
16 externally_managed: []const u8,
1517 fail: *ir.ErrorMsg,
1618};
1719
......@@ -20,7 +22,11 @@ pub fn generateSymbol(
2022 src: usize,
2123 typed_value: TypedValue,
2224 code: *std.ArrayList(u8),
23) error{OutOfMemory}!Result {
25) error{
26 OutOfMemory,
27 /// A Decl that this symbol depends on had a semantic analysis failure.
28 AnalysisFail,
29}!Result {
2430 switch (typed_value.ty.zigTypeTag()) {
2531 .Fn => {
2632 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
......@@ -45,12 +51,29 @@ pub fn generateSymbol(
4551 if (function.err_msg) |em| {
4652 return Result{ .fail = em };
4753 } else {
48 return Result{ .ok = code.items };
54 return Result{ .appended = {} };
4955 }
5056 },
5157 .Array => {
5258 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
53 return Result{ .ok = payload.data };
59 if (typed_value.ty.arraySentinel()) |sentinel| {
60 try code.ensureCapacity(code.items.len + payload.data.len + 1);
61 code.appendSliceAssumeCapacity(payload.data);
62 const prev_len = code.items.len;
63 switch (try generateSymbol(bin_file, src, .{
64 .ty = typed_value.ty.elemType(),
65 .val = sentinel,
66 }, code)) {
67 .appended => return Result{ .appended = {} },
68 .externally_managed => |slice| {
69 code.appendSliceAssumeCapacity(slice);
70 return Result{ .appended = {} };
71 },
72 .fail => |em| return Result{ .fail = em },
73 }
74 } else {
75 return Result{ .externally_managed = payload.data };
76 }
5477 }
5578 return Result{
5679 .fail = try ir.ErrorMsg.create(
......@@ -64,10 +87,11 @@ pub fn generateSymbol(
6487 .Pointer => {
6588 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
6689 const decl = payload.decl;
90 if (decl.analysis != .complete) return error.AnalysisFail;
6791 assert(decl.link.local_sym_index != 0);
6892 // TODO handle the dependency of this symbol on the decl's vaddr.
6993 // If the decl changes vaddr, then this symbol needs to get regenerated.
70 const vaddr = bin_file.symbols.items[decl.link.local_sym_index].st_value;
94 const vaddr = bin_file.local_symbols.items[decl.link.local_sym_index].st_value;
7195 const endian = bin_file.options.target.cpu.arch.endian();
7296 switch (bin_file.ptr_width) {
7397 .p32 => {
......@@ -79,7 +103,7 @@ pub fn generateSymbol(
79103 mem.writeInt(u64, code.items[0..8], vaddr, endian);
80104 },
81105 }
82 return Result{ .ok = code.items };
106 return Result{ .appended = {} };
83107 }
84108 return Result{
85109 .fail = try ir.ErrorMsg.create(
......@@ -90,6 +114,22 @@ pub fn generateSymbol(
90114 ),
91115 };
92116 },
117 .Int => {
118 const info = typed_value.ty.intInfo(bin_file.options.target);
119 if (info.bits == 8 and !info.signed) {
120 const x = typed_value.val.toUnsignedInt();
121 try code.append(@intCast(u8, x));
122 return Result{ .appended = {} };
123 }
124 return Result{
125 .fail = try ir.ErrorMsg.create(
126 bin_file.allocator,
127 src,
128 "TODO implement generateSymbol for int type '{}'",
129 .{typed_value.ty},
130 ),
131 };
132 },
93133 else => |t| {
94134 return Result{
95135 .fail = try ir.ErrorMsg.create(
src-self-hosted/ir.zig+11-2
......@@ -334,8 +334,14 @@ pub const Module = struct {
334334 }
335335
336336 pub fn dump(self: *Decl) void {
337 self.scope.dumpSrc(self.src);
338 std.debug.warn(" name={} status={}", .{ mem.spanZ(self.name), @tagName(self.analysis) });
337 const loc = std.zig.findLineColumn(self.scope.source.bytes, self.src);
338 std.debug.warn("{}:{}:{} name={} status={}", .{
339 self.scope.sub_file_path,
340 loc.line + 1,
341 loc.column + 1,
342 mem.spanZ(self.name),
343 @tagName(self.analysis),
344 });
339345 if (self.typedValueManaged()) |tvm| {
340346 std.debug.warn(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val });
341347 }
......@@ -721,6 +727,9 @@ pub const Module = struct {
721727
722728 self.bin_file.updateDecl(self, decl) catch |err| switch (err) {
723729 error.OutOfMemory => return error.OutOfMemory,
730 error.AnalysisFail => {
731 decl.analysis = .repeat_dependency_failure;
732 },
724733 else => {
725734 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
726735 self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
src-self-hosted/link.zig+104-93
......@@ -118,8 +118,12 @@ pub const ElfFile = struct {
118118 symtab_section_index: ?u16 = null,
119119 got_section_index: ?u16 = null,
120120
121 /// The same order as in the file
122 symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){},
121 /// The same order as in the file. ELF requires global symbols to all be after the
122 /// local symbols, they cannot be mixed. So we must buffer all the global symbols and
123 /// write them at the end. These are only the local symbols. The length of this array
124 /// is the value used for sh_info in the .symtab section.
125 local_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){},
126 global_symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = std.ArrayListUnmanaged(elf.Elf64_Sym){},
123127
124128 /// Same order as in the file. The value is the absolute vaddr value.
125129 /// If the vaddr of the executable program header changes, the entire
......@@ -130,7 +134,6 @@ pub const ElfFile = struct {
130134 shdr_table_dirty: bool = false,
131135 shstrtab_dirty: bool = false,
132136 offset_table_count_dirty: bool = false,
133 symbol_count_dirty: bool = false,
134137
135138 error_flags: ErrorFlags = ErrorFlags{},
136139
......@@ -156,14 +159,15 @@ pub const ElfFile = struct {
156159 };
157160
158161 pub const Export = struct {
159 sym_index: ?usize = null,
162 sym_index: ?u32 = null,
160163 };
161164
162165 pub fn deinit(self: *ElfFile) void {
163166 self.sections.deinit(self.allocator);
164167 self.program_headers.deinit(self.allocator);
165168 self.shstrtab.deinit(self.allocator);
166 self.symbols.deinit(self.allocator);
169 self.local_symbols.deinit(self.allocator);
170 self.global_symbols.deinit(self.allocator);
167171 self.offset_table.deinit(self.allocator);
168172 if (self.owns_file_handle)
169173 self.file.close();
......@@ -298,7 +302,10 @@ pub const ElfFile = struct {
298302 if (self.phdr_got_index == null) {
299303 self.phdr_got_index = @intCast(u16, self.program_headers.items.len);
300304 const file_size = @as(u64, ptr_size) * self.options.symbol_count_hint;
301 const off = self.findFreeSpace(file_size, ptr_size);
305 // We really only need ptr alignment but since we are using PROGBITS, linux requires
306 // page align.
307 const p_align = 0x1000;
308 const off = self.findFreeSpace(file_size, p_align);
302309 //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
303310 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
304311 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
......@@ -311,7 +318,7 @@ pub const ElfFile = struct {
311318 .p_vaddr = default_got_addr,
312319 .p_paddr = default_got_addr,
313320 .p_memsz = file_size,
314 .p_align = ptr_size,
321 .p_align = p_align,
315322 .p_flags = elf.PF_R,
316323 });
317324 self.phdr_table_dirty = true;
......@@ -369,7 +376,7 @@ pub const ElfFile = struct {
369376 .sh_link = 0,
370377 .sh_info = 0,
371378 .sh_addralign = phdr.p_align,
372 .sh_entsize = ptr_size,
379 .sh_entsize = 0,
373380 });
374381 self.shdr_table_dirty = true;
375382 }
......@@ -390,12 +397,12 @@ pub const ElfFile = struct {
390397 .sh_size = file_size,
391398 // The section header index of the associated string table.
392399 .sh_link = self.shstrtab_index.?,
393 .sh_info = @intCast(u32, self.symbols.items.len),
400 .sh_info = @intCast(u32, self.local_symbols.items.len),
394401 .sh_addralign = min_align,
395402 .sh_entsize = each_size,
396403 });
397404 self.shdr_table_dirty = true;
398 try self.writeAllSymbols();
405 try self.writeSymbol(0);
399406 }
400407 const shsize: u64 = switch (self.ptr_width) {
401408 .p32 => @sizeOf(elf.Elf32_Shdr),
......@@ -427,6 +434,10 @@ pub const ElfFile = struct {
427434 pub fn flush(self: *ElfFile) !void {
428435 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
429436
437 // Unfortunately these have to be buffered and done at the end because ELF does not allow
438 // mixing local and global symbols within a symbol table.
439 try self.writeAllGlobalSymbols();
440
430441 if (self.phdr_table_dirty) {
431442 const phsize: u64 = switch (self.ptr_width) {
432443 .p32 => @sizeOf(elf.Elf32_Phdr),
......@@ -552,8 +563,9 @@ pub const ElfFile = struct {
552563 assert(!self.phdr_table_dirty);
553564 assert(!self.shdr_table_dirty);
554565 assert(!self.shstrtab_dirty);
555 assert(!self.symbol_count_dirty);
556566 assert(!self.offset_table_count_dirty);
567 const syms_sect = &self.sections.items[self.symtab_section_index.?];
568 assert(syms_sect.sh_info == self.local_symbols.items.len);
557569 }
558570
559571 fn writeElfHeader(self: *ElfFile) !void {
......@@ -683,7 +695,7 @@ pub const ElfFile = struct {
683695 size_capacity: u64,
684696 };
685697
686 fn allocateTextBlock(self: *ElfFile, new_block_size: u64) !AllocatedBlock {
698 fn allocateTextBlock(self: *ElfFile, new_block_size: u64, alignment: u64) !AllocatedBlock {
687699 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
688700 const shdr = &self.sections.items[self.text_section_index.?];
689701
......@@ -692,14 +704,15 @@ pub const ElfFile = struct {
692704 // TODO instead of looping here, maintain a free list and a pointer to the end.
693705 var last_start: u64 = phdr.p_vaddr;
694706 var last_size: u64 = 0;
695 for (self.symbols.items) |sym| {
696 if (sym.st_value > last_start) {
707 for (self.local_symbols.items) |sym| {
708 if (sym.st_value + sym.st_size > last_start + last_size) {
697709 last_start = sym.st_value;
698710 last_size = sym.st_size;
699711 }
700712 }
701713 const end_vaddr = last_start + (last_size * alloc_num / alloc_den);
702 const needed_size = (end_vaddr + new_block_size) - phdr.p_vaddr;
714 const aligned_start_vaddr = mem.alignForwardGeneric(u64, end_vaddr, alignment);
715 const needed_size = (aligned_start_vaddr + new_block_size) - phdr.p_vaddr;
703716 if (needed_size > text_capacity) {
704717 // Must move the entire text section.
705718 const new_offset = self.findFreeSpace(needed_size, 0x1000);
......@@ -717,9 +730,9 @@ pub const ElfFile = struct {
717730 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
718731
719732 return AllocatedBlock{
720 .vaddr = end_vaddr,
721 .file_offset = shdr.sh_offset + (end_vaddr - phdr.p_vaddr),
722 .size_capacity = text_capacity - end_vaddr,
733 .vaddr = aligned_start_vaddr,
734 .file_offset = shdr.sh_offset + (aligned_start_vaddr - phdr.p_vaddr),
735 .size_capacity = text_capacity - needed_size,
723736 };
724737 }
725738
......@@ -731,7 +744,7 @@ pub const ElfFile = struct {
731744 // TODO look into using a hash map to speed up perf.
732745 const text_capacity = self.allocatedSize(shdr.sh_offset);
733746 var next_vaddr_start = phdr.p_vaddr + text_capacity;
734 for (self.symbols.items) |elem| {
747 for (self.local_symbols.items) |elem| {
735748 if (elem.st_value < sym.st_value) continue;
736749 if (elem.st_value < next_vaddr_start) next_vaddr_start = elem.st_value;
737750 }
......@@ -748,7 +761,8 @@ pub const ElfFile = struct {
748761
749762 const typed_value = decl.typed_value.most_recent.typed_value;
750763 const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) {
751 .ok => |x| x,
764 .externally_managed => |x| x,
765 .appended => code_buffer.items,
752766 .fail => |em| {
753767 decl.analysis = .codegen_failure;
754768 _ = try module.failed_decls.put(decl, em);
......@@ -756,20 +770,23 @@ pub const ElfFile = struct {
756770 },
757771 };
758772
773 const required_alignment = typed_value.ty.abiAlignment(self.options.target);
774
759775 const file_offset = blk: {
760 const code_size = code.len;
761776 const stt_bits: u8 = switch (typed_value.ty.zigTypeTag()) {
762777 .Fn => elf.STT_FUNC,
763778 else => elf.STT_OBJECT,
764779 };
765780
766781 if (decl.link.local_sym_index != 0) {
767 const local_sym = &self.symbols.items[decl.link.local_sym_index];
782 const local_sym = &self.local_symbols.items[decl.link.local_sym_index];
768783 const existing_block = self.findAllocatedTextBlock(local_sym.*);
769 const file_offset = if (code_size > existing_block.size_capacity) fo: {
770 const new_block = try self.allocateTextBlock(code_size);
784 const need_realloc = code.len > existing_block.size_capacity or
785 !mem.isAlignedGeneric(u64, local_sym.st_value, required_alignment);
786 const file_offset = if (need_realloc) fo: {
787 const new_block = try self.allocateTextBlock(code.len, required_alignment);
771788 local_sym.st_value = new_block.vaddr;
772 local_sym.st_size = code_size;
789 local_sym.st_size = code.len;
773790
774791 try self.writeOffsetTableEntry(decl.link.offset_table_index);
775792
......@@ -781,27 +798,27 @@ pub const ElfFile = struct {
781798 try self.writeSymbol(decl.link.local_sym_index);
782799 break :blk file_offset;
783800 } else {
784 try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + 1);
801 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);
785802 try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);
786803 const decl_name = mem.spanZ(decl.name);
787804 const name_str_index = try self.makeString(decl_name);
788 const new_block = try self.allocateTextBlock(code_size);
789 const local_sym_index = self.symbols.items.len;
805 const new_block = try self.allocateTextBlock(code.len, required_alignment);
806 const local_sym_index = self.local_symbols.items.len;
790807 const offset_table_index = self.offset_table.items.len;
791808
792 self.symbols.appendAssumeCapacity(.{
809 //std.debug.warn("add symbol for {} at vaddr 0x{x}, size {}\n", .{ decl.name, new_block.vaddr, code.len });
810 self.local_symbols.appendAssumeCapacity(.{
793811 .st_name = name_str_index,
794812 .st_info = (elf.STB_LOCAL << 4) | stt_bits,
795813 .st_other = 0,
796814 .st_shndx = self.text_section_index.?,
797815 .st_value = new_block.vaddr,
798 .st_size = code_size,
816 .st_size = code.len,
799817 });
800 errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1);
818 errdefer self.local_symbols.shrink(self.allocator, self.local_symbols.items.len - 1);
801819 self.offset_table.appendAssumeCapacity(new_block.vaddr);
802820 errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1);
803821
804 self.symbol_count_dirty = true;
805822 self.offset_table_count_dirty = true;
806823
807824 try self.writeSymbol(local_sym_index);
......@@ -830,10 +847,10 @@ pub const ElfFile = struct {
830847 decl: *const ir.Module.Decl,
831848 exports: []const *ir.Module.Export,
832849 ) !void {
833 try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + exports.len);
850 try self.global_symbols.ensureCapacity(self.allocator, self.global_symbols.items.len + exports.len);
834851 const typed_value = decl.typed_value.most_recent.typed_value;
835852 if (decl.link.local_sym_index == 0) return;
836 const decl_sym = self.symbols.items[decl.link.local_sym_index];
853 const decl_sym = self.local_symbols.items[decl.link.local_sym_index];
837854
838855 for (exports) |exp| {
839856 if (exp.options.section) |section_name| {
......@@ -866,7 +883,7 @@ pub const ElfFile = struct {
866883 };
867884 const stt_bits: u8 = @truncate(u4, decl_sym.st_info);
868885 if (exp.link.sym_index) |i| {
869 const sym = &self.symbols.items[i];
886 const sym = &self.global_symbols.items[i];
870887 sym.* = .{
871888 .st_name = try self.updateString(sym.st_name, exp.options.name),
872889 .st_info = (stb_bits << 4) | stt_bits,
......@@ -875,11 +892,10 @@ pub const ElfFile = struct {
875892 .st_value = decl_sym.st_value,
876893 .st_size = decl_sym.st_size,
877894 };
878 try self.writeSymbol(i);
879895 } else {
880896 const name = try self.makeString(exp.options.name);
881 const i = self.symbols.items.len;
882 self.symbols.appendAssumeCapacity(.{
897 const i = self.global_symbols.items.len;
898 self.global_symbols.appendAssumeCapacity(.{
883899 .st_name = name,
884900 .st_info = (stb_bits << 4) | stt_bits,
885901 .st_other = 0,
......@@ -887,11 +903,9 @@ pub const ElfFile = struct {
887903 .st_value = decl_sym.st_value,
888904 .st_size = decl_sym.st_size,
889905 });
890 errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1);
891 try self.writeSymbol(i);
906 errdefer self.global_symbols.shrink(self.allocator, self.global_symbols.items.len - 1);
892907
893 self.symbol_count_dirty = true;
894 exp.link.sym_index = i;
908 exp.link.sym_index = @intCast(u32, i);
895909 }
896910 }
897911 }
......@@ -944,13 +958,17 @@ pub const ElfFile = struct {
944958 fn writeOffsetTableEntry(self: *ElfFile, index: usize) !void {
945959 const shdr = &self.sections.items[self.got_section_index.?];
946960 const phdr = &self.program_headers.items[self.phdr_got_index.?];
961 const entry_size: u16 = switch (self.ptr_width) {
962 .p32 => 4,
963 .p64 => 8,
964 };
947965 if (self.offset_table_count_dirty) {
948966 // TODO Also detect virtual address collisions.
949967 const allocated_size = self.allocatedSize(shdr.sh_offset);
950 const needed_size = self.symbols.items.len * shdr.sh_entsize;
968 const needed_size = self.local_symbols.items.len * entry_size;
951969 if (needed_size > allocated_size) {
952970 // Must move the entire got section.
953 const new_offset = self.findFreeSpace(needed_size, @intCast(u16, shdr.sh_entsize));
971 const new_offset = self.findFreeSpace(needed_size, entry_size);
954972 const amt = try self.file.copyRangeAll(shdr.sh_offset, self.file, new_offset, shdr.sh_size);
955973 if (amt != shdr.sh_size) return error.InputOutput;
956974 shdr.sh_offset = new_offset;
......@@ -965,7 +983,7 @@ pub const ElfFile = struct {
965983 self.offset_table_count_dirty = false;
966984 }
967985 const endian = self.options.target.cpu.arch.endian();
968 const off = shdr.sh_offset + shdr.sh_entsize * index;
986 const off = shdr.sh_offset + @as(u64, entry_size) * index;
969987 switch (self.ptr_width) {
970988 .p32 => {
971989 var buf: [4]u8 = undefined;
......@@ -981,35 +999,42 @@ pub const ElfFile = struct {
981999 }
9821000
9831001 fn writeSymbol(self: *ElfFile, index: usize) !void {
984 assert(index != 0);
9851002 const syms_sect = &self.sections.items[self.symtab_section_index.?];
9861003 // Make sure we are not pointlessly writing symbol data that will have to get relocated
9871004 // due to running out of space.
988 if (self.symbol_count_dirty) {
1005 if (self.local_symbols.items.len != syms_sect.sh_info) {
9891006 const sym_size: u64 = switch (self.ptr_width) {
9901007 .p32 => @sizeOf(elf.Elf32_Sym),
9911008 .p64 => @sizeOf(elf.Elf64_Sym),
9921009 };
993 const allocated_size = self.allocatedSize(syms_sect.sh_offset);
994 const needed_size = self.symbols.items.len * sym_size;
995 if (needed_size > allocated_size) {
996 return self.writeAllSymbols();
1010 const sym_align: u16 = switch (self.ptr_width) {
1011 .p32 => @alignOf(elf.Elf32_Sym),
1012 .p64 => @alignOf(elf.Elf64_Sym),
1013 };
1014 const needed_size = (self.local_symbols.items.len + self.global_symbols.items.len) * sym_size;
1015 if (needed_size > self.allocatedSize(syms_sect.sh_offset)) {
1016 // Move all the symbols to a new file location.
1017 const new_offset = self.findFreeSpace(needed_size, sym_align);
1018 const existing_size = @as(u64, syms_sect.sh_info) * sym_size;
1019 const amt = try self.file.copyRangeAll(syms_sect.sh_offset, self.file, new_offset, existing_size);
1020 if (amt != existing_size) return error.InputOutput;
1021 syms_sect.sh_offset = new_offset;
9971022 }
998 syms_sect.sh_info = @intCast(u32, self.symbols.items.len);
1023 syms_sect.sh_info = @intCast(u32, self.local_symbols.items.len);
1024 syms_sect.sh_size = needed_size; // anticipating adding the global symbols later
9991025 self.shdr_table_dirty = true; // TODO look into only writing one section
1000 self.symbol_count_dirty = false;
10011026 }
10021027 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
10031028 switch (self.ptr_width) {
10041029 .p32 => {
10051030 var sym = [1]elf.Elf32_Sym{
10061031 .{
1007 .st_name = self.symbols.items[index].st_name,
1008 .st_value = @intCast(u32, self.symbols.items[index].st_value),
1009 .st_size = @intCast(u32, self.symbols.items[index].st_size),
1010 .st_info = self.symbols.items[index].st_info,
1011 .st_other = self.symbols.items[index].st_other,
1012 .st_shndx = self.symbols.items[index].st_shndx,
1032 .st_name = self.local_symbols.items[index].st_name,
1033 .st_value = @intCast(u32, self.local_symbols.items[index].st_value),
1034 .st_size = @intCast(u32, self.local_symbols.items[index].st_size),
1035 .st_info = self.local_symbols.items[index].st_info,
1036 .st_other = self.local_symbols.items[index].st_other,
1037 .st_shndx = self.local_symbols.items[index].st_shndx,
10131038 },
10141039 };
10151040 if (foreign_endian) {
......@@ -1019,7 +1044,7 @@ pub const ElfFile = struct {
10191044 try self.file.pwriteAll(mem.sliceAsBytes(sym[0..1]), off);
10201045 },
10211046 .p64 => {
1022 var sym = [1]elf.Elf64_Sym{self.symbols.items[index]};
1047 var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]};
10231048 if (foreign_endian) {
10241049 bswapAllFields(elf.Elf64_Sym, &sym[0]);
10251050 }
......@@ -1029,67 +1054,53 @@ pub const ElfFile = struct {
10291054 }
10301055 }
10311056
1032 fn writeAllSymbols(self: *ElfFile) !void {
1057 fn writeAllGlobalSymbols(self: *ElfFile) !void {
10331058 const syms_sect = &self.sections.items[self.symtab_section_index.?];
1034 const sym_align: u16 = switch (self.ptr_width) {
1035 .p32 => @alignOf(elf.Elf32_Sym),
1036 .p64 => @alignOf(elf.Elf64_Sym),
1037 };
10381059 const sym_size: u64 = switch (self.ptr_width) {
10391060 .p32 => @sizeOf(elf.Elf32_Sym),
10401061 .p64 => @sizeOf(elf.Elf64_Sym),
10411062 };
1042 const allocated_size = self.allocatedSize(syms_sect.sh_offset);
1043 const needed_size = self.symbols.items.len * sym_size;
1044 if (needed_size > allocated_size) {
1045 syms_sect.sh_size = 0; // free the space
1046 syms_sect.sh_offset = self.findFreeSpace(needed_size, sym_align);
1047 //std.debug.warn("moved symtab to 0x{x} to 0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size });
1048 }
10491063 //std.debug.warn("symtab start=0x{x} end=0x{x}\n", .{ syms_sect.sh_offset, syms_sect.sh_offset + needed_size });
1050 syms_sect.sh_size = needed_size;
1051 syms_sect.sh_info = @intCast(u32, self.symbols.items.len);
1052 self.symbol_count_dirty = false;
1053 self.shdr_table_dirty = true; // TODO look into only writing one section
10541064 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
1065 const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size;
10551066 switch (self.ptr_width) {
10561067 .p32 => {
1057 const buf = try self.allocator.alloc(elf.Elf32_Sym, self.symbols.items.len);
1068 const buf = try self.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len);
10581069 defer self.allocator.free(buf);
10591070
10601071 for (buf) |*sym, i| {
10611072 sym.* = .{
1062 .st_name = self.symbols.items[i].st_name,
1063 .st_value = @intCast(u32, self.symbols.items[i].st_value),
1064 .st_size = @intCast(u32, self.symbols.items[i].st_size),
1065 .st_info = self.symbols.items[i].st_info,
1066 .st_other = self.symbols.items[i].st_other,
1067 .st_shndx = self.symbols.items[i].st_shndx,
1073 .st_name = self.global_symbols.items[i].st_name,
1074 .st_value = @intCast(u32, self.global_symbols.items[i].st_value),
1075 .st_size = @intCast(u32, self.global_symbols.items[i].st_size),
1076 .st_info = self.global_symbols.items[i].st_info,
1077 .st_other = self.global_symbols.items[i].st_other,
1078 .st_shndx = self.global_symbols.items[i].st_shndx,
10681079 };
10691080 if (foreign_endian) {
10701081 bswapAllFields(elf.Elf32_Sym, sym);
10711082 }
10721083 }
1073 try self.file.pwriteAll(mem.sliceAsBytes(buf), syms_sect.sh_offset);
1084 try self.file.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
10741085 },
10751086 .p64 => {
1076 const buf = try self.allocator.alloc(elf.Elf64_Sym, self.symbols.items.len);
1087 const buf = try self.allocator.alloc(elf.Elf64_Sym, self.global_symbols.items.len);
10771088 defer self.allocator.free(buf);
10781089
10791090 for (buf) |*sym, i| {
10801091 sym.* = .{
1081 .st_name = self.symbols.items[i].st_name,
1082 .st_value = self.symbols.items[i].st_value,
1083 .st_size = self.symbols.items[i].st_size,
1084 .st_info = self.symbols.items[i].st_info,
1085 .st_other = self.symbols.items[i].st_other,
1086 .st_shndx = self.symbols.items[i].st_shndx,
1092 .st_name = self.global_symbols.items[i].st_name,
1093 .st_value = self.global_symbols.items[i].st_value,
1094 .st_size = self.global_symbols.items[i].st_size,
1095 .st_info = self.global_symbols.items[i].st_info,
1096 .st_other = self.global_symbols.items[i].st_other,
1097 .st_shndx = self.global_symbols.items[i].st_shndx,
10871098 };
10881099 if (foreign_endian) {
10891100 bswapAllFields(elf.Elf64_Sym, sym);
10901101 }
10911102 }
1092 try self.file.pwriteAll(mem.sliceAsBytes(buf), syms_sect.sh_offset);
1103 try self.file.pwriteAll(mem.sliceAsBytes(buf), global_syms_off);
10931104 },
10941105 }
10951106 }
......@@ -1126,7 +1137,7 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !El
11261137 errdefer self.deinit();
11271138
11281139 // Index 0 is always a null symbol.
1129 try self.symbols.append(allocator, .{
1140 try self.local_symbols.append(allocator, .{
11301141 .st_name = 0,
11311142 .st_info = 0,
11321143 .st_other = 0,
src-self-hosted/type.zig+108-4
......@@ -287,12 +287,12 @@ pub const Type = extern union {
287287 .fn_naked_noreturn_no_args,
288288 .fn_ccc_void_no_args,
289289 .single_const_pointer_to_comptime_int,
290 .const_slice_u8, // See last_no_payload_tag below.
290 .const_slice_u8,
291291 .array_u8_sentinel_0,
292 .array,
292 .array, // TODO check for zero bits
293293 .single_const_pointer,
294 .int_signed,
295 .int_unsigned,
294 .int_signed, // TODO check for zero bits
295 .int_unsigned, // TODO check for zero bits
296296 => true,
297297
298298 .c_void,
......@@ -306,6 +306,66 @@ pub const Type = extern union {
306306 };
307307 }
308308
309 /// Asserts that hasCodeGenBits() is true.
310 pub fn abiAlignment(self: Type, target: Target) u32 {
311 return switch (self.tag()) {
312 .u8,
313 .i8,
314 .bool,
315 .fn_noreturn_no_args, // represents machine code; not a pointer
316 .fn_naked_noreturn_no_args, // represents machine code; not a pointer
317 .fn_ccc_void_no_args, // represents machine code; not a pointer
318 .array_u8_sentinel_0,
319 => return 1,
320
321 .isize,
322 .usize,
323 .single_const_pointer_to_comptime_int,
324 .const_slice_u8,
325 .single_const_pointer,
326 => return @divExact(target.cpu.arch.ptrBitWidth(), 8),
327
328 .c_short => return @divExact(CType.short.sizeInBits(target), 8),
329 .c_ushort => return @divExact(CType.ushort.sizeInBits(target), 8),
330 .c_int => return @divExact(CType.int.sizeInBits(target), 8),
331 .c_uint => return @divExact(CType.uint.sizeInBits(target), 8),
332 .c_long => return @divExact(CType.long.sizeInBits(target), 8),
333 .c_ulong => return @divExact(CType.ulong.sizeInBits(target), 8),
334 .c_longlong => return @divExact(CType.longlong.sizeInBits(target), 8),
335 .c_ulonglong => return @divExact(CType.ulonglong.sizeInBits(target), 8),
336
337 .f16 => return 2,
338 .f32 => return 4,
339 .f64 => return 8,
340 .f128 => return 16,
341 .c_longdouble => return 16,
342
343 .anyerror => return 2, // TODO revisit this when we have the concept of the error tag type
344
345 .array => return self.cast(Payload.Array).?.elem_type.abiAlignment(target),
346
347 .int_signed, .int_unsigned => {
348 const bits: u16 = if (self.cast(Payload.IntSigned)) |pl|
349 pl.bits
350 else if (self.cast(Payload.IntUnsigned)) |pl|
351 pl.bits
352 else
353 unreachable;
354
355 return std.math.ceilPowerOfTwoPromote(u16, (bits + 7) / 8);
356 },
357
358 .c_void,
359 .void,
360 .type,
361 .comptime_int,
362 .comptime_float,
363 .noreturn,
364 .@"null",
365 => unreachable,
366 };
367 }
368
309369 pub fn isSinglePointer(self: Type) bool {
310370 return switch (self.tag()) {
311371 .u8,
......@@ -525,6 +585,50 @@ pub const Type = extern union {
525585 };
526586 }
527587
588 /// Asserts the type is an array or vector.
589 pub fn arraySentinel(self: Type) ?Value {
590 return switch (self.tag()) {
591 .u8,
592 .i8,
593 .isize,
594 .usize,
595 .c_short,
596 .c_ushort,
597 .c_int,
598 .c_uint,
599 .c_long,
600 .c_ulong,
601 .c_longlong,
602 .c_ulonglong,
603 .c_longdouble,
604 .f16,
605 .f32,
606 .f64,
607 .f128,
608 .c_void,
609 .bool,
610 .void,
611 .type,
612 .anyerror,
613 .comptime_int,
614 .comptime_float,
615 .noreturn,
616 .@"null",
617 .fn_noreturn_no_args,
618 .fn_naked_noreturn_no_args,
619 .fn_ccc_void_no_args,
620 .single_const_pointer,
621 .single_const_pointer_to_comptime_int,
622 .const_slice_u8,
623 .int_unsigned,
624 .int_signed,
625 => unreachable,
626
627 .array => return null,
628 .array_u8_sentinel_0 => return Value.initTag(.zero),
629 };
630 }
631
528632 /// Returns true if and only if the type is a fixed-width, signed integer.
529633 pub fn isSignedInt(self: Type) bool {
530634 return switch (self.tag()) {