authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-19 13:33:36-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-19 13:33:36-04:00
log8d812dba30fe3c17e9d64607fdf813977eaf0496
tree84dba7aad60ad2472da927d65ffffa7090386a6d
parent1cde0edff469fbe5ee62cb10a44161b4c9910f98

stage2: set up a trampoline table for functions

However there does not appear to be an x86 encoding for calling an immediate address. So there's no point of setting this up. We should just emit an indirect call to the got addr.

3 files changed, 183 insertions(+), 34 deletions(-)

src-self-hosted/Module.zig+8-9
...@@ -231,6 +231,7 @@ pub const Fn = struct {...@@ -231,6 +231,7 @@ pub const Fn = struct {
231 dependency_failure,231 dependency_failure,
232 success: Body,232 success: Body,
233 },233 },
234 owner_decl: *Decl,
234235
235 /// This memory is temporary and points to stack memory for the duration236 /// This memory is temporary and points to stack memory for the duration
236 /// of Fn analysis.237 /// of Fn analysis.
...@@ -883,14 +884,6 @@ fn resolveDecl(...@@ -883,14 +884,6 @@ fn resolveDecl(
883 };884 };
884 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);885 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
885886
886 const has_codegen_bits = typed_value.ty.hasCodeGenBits();
887 if (has_codegen_bits) {
888 // We don't fully codegen the decl until later, but we do need to reserve a global
889 // offset table index for it. This allows us to codegen decls out of dependency order,
890 // increasing how many computations can be done in parallel.
891 try self.bin_file.allocateDeclIndexes(new_decl);
892 }
893
894 arena_state.* = decl_scope.arena.state;887 arena_state.* = decl_scope.arena.state;
895888
896 new_decl.typed_value = .{889 new_decl.typed_value = .{
...@@ -900,7 +893,12 @@ fn resolveDecl(...@@ -900,7 +893,12 @@ fn resolveDecl(
900 },893 },
901 };894 };
902 new_decl.analysis = .complete;895 new_decl.analysis = .complete;
903 if (has_codegen_bits) {896 if (typed_value.ty.hasCodeGenBits()) {
897 // We don't fully codegen the decl until later, but we do need to reserve a global
898 // offset table index for it. This allows us to codegen decls out of dependency order,
899 // increasing how many computations can be done in parallel.
900 try self.bin_file.allocateDeclIndexes(new_decl);
901
904 // We ensureCapacity when scanning for decls.902 // We ensureCapacity when scanning for decls.
905 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });903 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });
906 }904 }
...@@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError...@@ -1329,6 +1327,7 @@ fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError
1329 new_func.* = .{1327 new_func.* = .{
1330 .fn_type = fn_type,1328 .fn_type = fn_type,
1331 .analysis = .{ .queued = fn_inst },1329 .analysis = .{ .queued = fn_inst },
1330 .owner_decl = scope.decl(),
1332 };1331 };
1333 const fn_payload = try scope.arena().create(Value.Payload.Function);1332 const fn_payload = try scope.arena().create(Value.Payload.Function);
1334 fn_payload.* = .{ .func = new_func };1333 fn_payload.* = .{ .func = new_func };
src-self-hosted/codegen.zig+33-2
...@@ -19,6 +19,24 @@ pub const Result = union(enum) {...@@ -19,6 +19,24 @@ pub const Result = union(enum) {
19 fail: *Module.ErrorMsg,19 fail: *Module.ErrorMsg,
20};20};
2121
22pub fn pltEntrySize(target: Target) u16 {
23 return switch (target.cpu.arch) {
24 .i386, .x86_64 => 5,
25 else => @panic("TODO implement pltEntrySize for more architectures"),
26 };
27}
28
29pub fn writePltEntry(target: Target, buf: []u8, addr: u32) void {
30 switch (target.cpu.arch) {
31 .i386, .x86_64 => {
32 // 9a xx xx xx xx call addr
33 buf[0] = 0x9a;
34 mem.writeIntLittle(u32, buf[1..5], addr);
35 },
36 else => @panic("TODO implement pltEntrySize for more architectures"),
37 }
38}
39
22pub fn generateSymbol(40pub fn generateSymbol(
23 bin_file: *link.ElfFile,41 bin_file: *link.ElfFile,
24 src: usize,42 src: usize,
...@@ -203,7 +221,20 @@ const Function = struct {...@@ -203,7 +221,20 @@ const Function = struct {
203221
204 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {222 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
205 const func = func_val.func;223 const func = func_val.func;
206 return self.fail(inst.base.src, "TODO implement calling function", .{});224 const plt_index = func.owner_decl.link.offset_table_index.plt;
225 const plt = &self.bin_file.program_headers.items[self.bin_file.phdr_got_plt_index.?];
226 const plt_entry_size = pltEntrySize(self.target.*);
227 const plt_addr = @intCast(u32, plt.p_vaddr + func.owner_decl.link.offset_table_index.plt * plt_entry_size);
228 // ea xx xx xx xx jmp addr
229 try self.code.resize(self.code.items.len + 5);
230 self.code.items[self.code.items.len - 5] = 0xea;
231 mem.writeIntLittle(u32, self.code.items[self.code.items.len - 4 ..][0..4], plt_addr);
232 const return_type = func.fn_type.fnReturnType();
233 switch (return_type.zigTypeTag()) {
234 .Void => return MCValue{ .none = {} },
235 .NoReturn => return MCValue{ .unreach = {} },
236 else => return self.fail(inst.base.src, "TODO implement fn call with non-void return value", .{}),
237 }
207 } else {238 } else {
208 return self.fail(inst.base.src, "TODO implement calling weird function values", .{});239 return self.fail(inst.base.src, "TODO implement calling weird function values", .{});
209 }240 }
...@@ -575,7 +606,7 @@ const Function = struct {...@@ -575,7 +606,7 @@ const Function = struct {
575 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {606 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
576 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];607 const got = &self.bin_file.program_headers.items[self.bin_file.phdr_got_index.?];
577 const decl = payload.decl;608 const decl = payload.decl;
578 const got_addr = got.p_vaddr + decl.link.offset_table_index * ptr_bytes;609 const got_addr = got.p_vaddr + decl.link.offset_table_index.got * ptr_bytes;
579 return MCValue{ .memory = got_addr };610 return MCValue{ .memory = got_addr };
580 }611 }
581 return self.fail(src, "TODO codegen more kinds of const pointers", .{});612 return self.fail(src, "TODO codegen more kinds of const pointers", .{});
src-self-hosted/link.zig+142-23
...@@ -110,6 +110,7 @@ pub const ElfFile = struct {...@@ -110,6 +110,7 @@ pub const ElfFile = struct {
110 /// The index into the program headers of the global offset table.110 /// The index into the program headers of the global offset table.
111 /// It needs PT_LOAD and Read flags.111 /// It needs PT_LOAD and Read flags.
112 phdr_got_index: ?u16 = null,112 phdr_got_index: ?u16 = null,
113 phdr_got_plt_index: ?u16 = null,
113 entry_addr: ?u64 = null,114 entry_addr: ?u64 = null,
114115
115 shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},116 shstrtab: std.ArrayListUnmanaged(u8) = std.ArrayListUnmanaged(u8){},
...@@ -118,6 +119,7 @@ pub const ElfFile = struct {...@@ -118,6 +119,7 @@ pub const ElfFile = struct {
118 text_section_index: ?u16 = null,119 text_section_index: ?u16 = null,
119 symtab_section_index: ?u16 = null,120 symtab_section_index: ?u16 = null,
120 got_section_index: ?u16 = null,121 got_section_index: ?u16 = null,
122 got_plt_section_index: ?u16 = null,
121123
122 /// The same order as in the file. ELF requires global symbols to all be after the124 /// The same order as in the file. ELF requires global symbols to all be after the
123 /// local symbols, they cannot be mixed. So we must buffer all the global symbols and125 /// local symbols, they cannot be mixed. So we must buffer all the global symbols and
...@@ -130,11 +132,16 @@ pub const ElfFile = struct {...@@ -130,11 +132,16 @@ pub const ElfFile = struct {
130 /// If the vaddr of the executable program header changes, the entire132 /// If the vaddr of the executable program header changes, the entire
131 /// offset table needs to be rewritten.133 /// offset table needs to be rewritten.
132 offset_table: std.ArrayListUnmanaged(u64) = std.ArrayListUnmanaged(u64){},134 offset_table: std.ArrayListUnmanaged(u64) = std.ArrayListUnmanaged(u64){},
135 /// Same order as in the file. The value is the absolute vaddr value.
136 /// If the vaddr of the executable program header changes, the entire
137 /// fn trampoline table needs to be rewritten.
138 fn_trampoline_table: std.ArrayListUnmanaged(u64) = std.ArrayListUnmanaged(u64){},
133139
134 phdr_table_dirty: bool = false,140 phdr_table_dirty: bool = false,
135 shdr_table_dirty: bool = false,141 shdr_table_dirty: bool = false,
136 shstrtab_dirty: bool = false,142 shstrtab_dirty: bool = false,
137 offset_table_count_dirty: bool = false,143 offset_table_count_dirty: bool = false,
144 fn_trampoline_table_count_dirty: bool = false,
138145
139 error_flags: ErrorFlags = ErrorFlags{},146 error_flags: ErrorFlags = ErrorFlags{},
140147
...@@ -150,12 +157,18 @@ pub const ElfFile = struct {...@@ -150,12 +157,18 @@ pub const ElfFile = struct {
150 /// If this field is 0, it means the codegen size = 0 and there is no symbol or157 /// If this field is 0, it means the codegen size = 0 and there is no symbol or
151 /// offset table entry.158 /// offset table entry.
152 local_sym_index: u32,159 local_sym_index: u32,
153 /// This field is undefined for symbols with size = 0.160 /// when size = 0 and there is no offset table index
154 offset_table_index: u32,161 offset_table_index: union {
162 unallocated: void,
163 /// This is an index into offset_table
164 got: u32,
165 /// This is an index into fn_trampoline_table
166 plt: u32,
167 },
155168
156 pub const empty = Decl{169 pub const empty = Decl{
157 .local_sym_index = 0,170 .local_sym_index = 0,
158 .offset_table_index = undefined,171 .offset_table_index = .{ .unallocated = {} },
159 };172 };
160 };173 };
161174
...@@ -170,6 +183,7 @@ pub const ElfFile = struct {...@@ -170,6 +183,7 @@ pub const ElfFile = struct {
170 self.local_symbols.deinit(self.allocator);183 self.local_symbols.deinit(self.allocator);
171 self.global_symbols.deinit(self.allocator);184 self.global_symbols.deinit(self.allocator);
172 self.offset_table.deinit(self.allocator);185 self.offset_table.deinit(self.allocator);
186 self.fn_trampoline_table.deinit(self.allocator);
173 if (self.owns_file_handle) {187 if (self.owns_file_handle) {
174 if (self.file) |f| f.close();188 if (self.file) |f| f.close();
175 }189 }
...@@ -343,6 +357,30 @@ pub const ElfFile = struct {...@@ -343,6 +357,30 @@ pub const ElfFile = struct {
343 });357 });
344 self.phdr_table_dirty = true;358 self.phdr_table_dirty = true;
345 }359 }
360 if (self.phdr_got_plt_index == null) {
361 self.phdr_got_plt_index = @intCast(u16, self.program_headers.items.len);
362 const file_size = @as(u64, ptr_size) * self.options.symbol_count_hint;
363 // We really only need ptr alignment but since we are using PROGBITS, linux requires
364 // page align.
365 const p_align = 0x1000;
366 const off = self.findFreeSpace(file_size, p_align);
367 //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
368 // TODO instead of hard coding the vaddr, make a function to find a vaddr to put things at.
369 // we'll need to re-use that function anyway, in case the GOT grows and overlaps something
370 // else in virtual memory.
371 const default_got_plt_addr = 0x6000000;
372 try self.program_headers.append(self.allocator, .{
373 .p_type = elf.PT_LOAD,
374 .p_offset = off,
375 .p_filesz = file_size,
376 .p_vaddr = default_got_plt_addr,
377 .p_paddr = default_got_plt_addr,
378 .p_memsz = file_size,
379 .p_align = p_align,
380 .p_flags = elf.PF_R,
381 });
382 self.phdr_table_dirty = true;
383 }
346 if (self.shstrtab_index == null) {384 if (self.shstrtab_index == null) {
347 self.shstrtab_index = @intCast(u16, self.sections.items.len);385 self.shstrtab_index = @intCast(u16, self.sections.items.len);
348 assert(self.shstrtab.items.len == 0);386 assert(self.shstrtab.items.len == 0);
...@@ -400,6 +438,24 @@ pub const ElfFile = struct {...@@ -400,6 +438,24 @@ pub const ElfFile = struct {
400 });438 });
401 self.shdr_table_dirty = true;439 self.shdr_table_dirty = true;
402 }440 }
441 if (self.got_plt_section_index == null) {
442 self.got_plt_section_index = @intCast(u16, self.sections.items.len);
443 const phdr = &self.program_headers.items[self.phdr_got_plt_index.?];
444
445 try self.sections.append(self.allocator, .{
446 .sh_name = try self.makeString(".got.plt"),
447 .sh_type = elf.SHT_PROGBITS,
448 .sh_flags = elf.SHF_ALLOC,
449 .sh_addr = phdr.p_vaddr,
450 .sh_offset = phdr.p_offset,
451 .sh_size = phdr.p_filesz,
452 .sh_link = 0,
453 .sh_info = 0,
454 .sh_addralign = phdr.p_align,
455 .sh_entsize = 0,
456 });
457 self.shdr_table_dirty = true;
458 }
403 if (self.symtab_section_index == null) {459 if (self.symtab_section_index == null) {
404 self.symtab_section_index = @intCast(u16, self.sections.items.len);460 self.symtab_section_index = @intCast(u16, self.sections.items.len);
405 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);461 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
...@@ -584,6 +640,7 @@ pub const ElfFile = struct {...@@ -584,6 +640,7 @@ pub const ElfFile = struct {
584 assert(!self.shdr_table_dirty);640 assert(!self.shdr_table_dirty);
585 assert(!self.shstrtab_dirty);641 assert(!self.shstrtab_dirty);
586 assert(!self.offset_table_count_dirty);642 assert(!self.offset_table_count_dirty);
643 assert(!self.fn_trampoline_table_count_dirty);
587 const syms_sect = &self.sections.items[self.symtab_section_index.?];644 const syms_sect = &self.sections.items[self.symtab_section_index.?];
588 assert(syms_sect.sh_info == self.local_symbols.items.len);645 assert(syms_sect.sh_info == self.local_symbols.items.len);
589 }646 }
...@@ -740,6 +797,7 @@ pub const ElfFile = struct {...@@ -740,6 +797,7 @@ pub const ElfFile = struct {
740 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size);797 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, text_size);
741 if (amt != text_size) return error.InputOutput;798 if (amt != text_size) return error.InputOutput;
742 shdr.sh_offset = new_offset;799 shdr.sh_offset = new_offset;
800 phdr.p_offset = new_offset;
743 }801 }
744 // Now that we know the code size, we need to update the program header for executable code802 // Now that we know the code size, we need to update the program header for executable code
745 shdr.sh_size = needed_size;803 shdr.sh_size = needed_size;
...@@ -778,10 +836,14 @@ pub const ElfFile = struct {...@@ -778,10 +836,14 @@ pub const ElfFile = struct {
778 pub fn allocateDeclIndexes(self: *ElfFile, decl: *Module.Decl) !void {836 pub fn allocateDeclIndexes(self: *ElfFile, decl: *Module.Decl) !void {
779 if (decl.link.local_sym_index != 0) return;837 if (decl.link.local_sym_index != 0) return;
780838
839 const is_fn = (decl.typed_value.most_recent.typed_value.ty.zigTypeTag() == .Fn);
840
781 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);841 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);
782 try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);842 try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);
843 try self.fn_trampoline_table.ensureCapacity(self.allocator, self.fn_trampoline_table.items.len + 1);
783 const local_sym_index = self.local_symbols.items.len;844 const local_sym_index = self.local_symbols.items.len;
784 const offset_table_index = self.offset_table.items.len;845 const offset_table_index = self.offset_table.items.len;
846 const fn_trampoline_table_index = self.fn_trampoline_table.items.len;
785 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];847 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
786848
787 self.local_symbols.appendAssumeCapacity(.{849 self.local_symbols.appendAssumeCapacity(.{
...@@ -792,15 +854,20 @@ pub const ElfFile = struct {...@@ -792,15 +854,20 @@ pub const ElfFile = struct {
792 .st_value = phdr.p_vaddr,854 .st_value = phdr.p_vaddr,
793 .st_size = 0,855 .st_size = 0,
794 });856 });
795 errdefer self.local_symbols.shrink(self.allocator, self.local_symbols.items.len - 1);857 if (is_fn) {
796 self.offset_table.appendAssumeCapacity(0);858 self.fn_trampoline_table.appendAssumeCapacity(0);
797 errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1);859 self.fn_trampoline_table_count_dirty = true;
798860 } else {
799 self.offset_table_count_dirty = true;861 self.offset_table.appendAssumeCapacity(0);
862 self.offset_table_count_dirty = true;
863 }
800864
801 decl.link = .{865 decl.link = .{
802 .local_sym_index = @intCast(u32, local_sym_index),866 .local_sym_index = @intCast(u32, local_sym_index),
803 .offset_table_index = @intCast(u32, offset_table_index),867 .offset_table_index = if (is_fn)
868 .{ .plt = @intCast(u32, fn_trampoline_table_index) }
869 else
870 .{ .got = @intCast(u32, offset_table_index) },
804 };871 };
805 }872 }
806873
...@@ -818,6 +885,7 @@ pub const ElfFile = struct {...@@ -818,6 +885,7 @@ pub const ElfFile = struct {
818 return;885 return;
819 },886 },
820 };887 };
888 const is_fn = (typed_value.ty.zigTypeTag() == .Fn);
821889
822 const required_alignment = typed_value.ty.abiAlignment(self.options.target);890 const required_alignment = typed_value.ty.abiAlignment(self.options.target);
823891
...@@ -837,14 +905,13 @@ pub const ElfFile = struct {...@@ -837,14 +905,13 @@ pub const ElfFile = struct {
837 const file_offset = if (need_realloc) fo: {905 const file_offset = if (need_realloc) fo: {
838 const new_block = try self.allocateTextBlock(code.len, required_alignment);906 const new_block = try self.allocateTextBlock(code.len, required_alignment);
839 local_sym.st_value = new_block.vaddr;907 local_sym.st_value = new_block.vaddr;
840 self.offset_table.items[decl.link.offset_table_index] = new_block.vaddr;908 if (is_fn) {
841909 self.fn_trampoline_table.items[decl.link.offset_table_index.plt] = new_block.vaddr;
842 //std.debug.warn("{}: writing got index {}=0x{x}\n", .{910 try self.writeFnTrampolineEntry(decl.link.offset_table_index.plt);
843 // decl.name,911 } else {
844 // decl.link.offset_table_index,912 self.offset_table.items[decl.link.offset_table_index.got] = new_block.vaddr;
845 // self.offset_table.items[decl.link.offset_table_index],913 try self.writeOffsetTableEntry(decl.link.offset_table_index.got);
846 //});914 }
847 try self.writeOffsetTableEntry(decl.link.offset_table_index);
848915
849 break :fo new_block.file_offset;916 break :fo new_block.file_offset;
850 } else existing_block.file_offset;917 } else existing_block.file_offset;
...@@ -861,11 +928,13 @@ pub const ElfFile = struct {...@@ -861,11 +928,13 @@ pub const ElfFile = struct {
861 } else {928 } else {
862 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);929 try self.local_symbols.ensureCapacity(self.allocator, self.local_symbols.items.len + 1);
863 try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);930 try self.offset_table.ensureCapacity(self.allocator, self.offset_table.items.len + 1);
931 try self.fn_trampoline_table.ensureCapacity(self.allocator, self.fn_trampoline_table.items.len + 1);
864 const decl_name = mem.spanZ(decl.name);932 const decl_name = mem.spanZ(decl.name);
865 const name_str_index = try self.makeString(decl_name);933 const name_str_index = try self.makeString(decl_name);
866 const new_block = try self.allocateTextBlock(code.len, required_alignment);934 const new_block = try self.allocateTextBlock(code.len, required_alignment);
867 const local_sym_index = self.local_symbols.items.len;935 const local_sym_index = self.local_symbols.items.len;
868 const offset_table_index = self.offset_table.items.len;936 const offset_table_index = self.offset_table.items.len;
937 const fn_trampoline_table_index = self.fn_trampoline_table.items.len;
869938
870 //std.debug.warn("add symbol for {} at vaddr 0x{x}, size {}\n", .{ decl.name, new_block.vaddr, code.len });939 //std.debug.warn("add symbol for {} at vaddr 0x{x}, size {}\n", .{ decl.name, new_block.vaddr, code.len });
871 self.local_symbols.appendAssumeCapacity(.{940 self.local_symbols.appendAssumeCapacity(.{
...@@ -877,17 +946,32 @@ pub const ElfFile = struct {...@@ -877,17 +946,32 @@ pub const ElfFile = struct {
877 .st_size = code.len,946 .st_size = code.len,
878 });947 });
879 errdefer self.local_symbols.shrink(self.allocator, self.local_symbols.items.len - 1);948 errdefer self.local_symbols.shrink(self.allocator, self.local_symbols.items.len - 1);
880 self.offset_table.appendAssumeCapacity(new_block.vaddr);949 if (is_fn) {
881 errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1);950 self.fn_trampoline_table.appendAssumeCapacity(new_block.vaddr);
882951 } else {
883 self.offset_table_count_dirty = true;952 self.offset_table.appendAssumeCapacity(new_block.vaddr);
953 }
954 errdefer if (is_fn) {
955 self.fn_trampoline_table.shrink(self.allocator, self.fn_trampoline_table.items.len - 1);
956 } else {
957 self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1);
958 };
884959
885 try self.writeSymbol(local_sym_index);960 try self.writeSymbol(local_sym_index);
886 try self.writeOffsetTableEntry(offset_table_index);961 if (is_fn) {
962 try self.writeFnTrampolineEntry(fn_trampoline_table_index);
963 self.fn_trampoline_table_count_dirty = true;
964 } else {
965 try self.writeOffsetTableEntry(offset_table_index);
966 self.offset_table_count_dirty = true;
967 }
887968
888 decl.link = .{969 decl.link = .{
889 .local_sym_index = @intCast(u32, local_sym_index),970 .local_sym_index = @intCast(u32, local_sym_index),
890 .offset_table_index = @intCast(u32, offset_table_index),971 .offset_table_index = if (is_fn)
972 .{ .plt = @intCast(u32, fn_trampoline_table_index) }
973 else
974 .{ .got = @intCast(u32, offset_table_index) },
891 };975 };
892976
893 //std.debug.warn("writing new {} at vaddr 0x{x}\n", .{ decl.name, new_block.vaddr });977 //std.debug.warn("writing new {} at vaddr 0x{x}\n", .{ decl.name, new_block.vaddr });
...@@ -1017,6 +1101,40 @@ pub const ElfFile = struct {...@@ -1017,6 +1101,40 @@ pub const ElfFile = struct {
1017 }1101 }
1018 }1102 }
10191103
1104 fn writeFnTrampolineEntry(self: *ElfFile, index: usize) !void {
1105 const shdr = &self.sections.items[self.got_plt_section_index.?];
1106 const phdr = &self.program_headers.items[self.phdr_got_plt_index.?];
1107 const entry_size = codegen.pltEntrySize(self.options.target);
1108 var entry_buf: [16]u8 = undefined;
1109 assert(entry_size <= entry_buf.len);
1110
1111 if (self.fn_trampoline_table_count_dirty) {
1112 // TODO Also detect virtual address collisions.
1113 const allocated_size = self.allocatedSize(shdr.sh_offset);
1114 const needed_size = self.local_symbols.items.len * entry_size;
1115 if (needed_size > allocated_size) {
1116 // Must move the entire .got.plt section.
1117 const new_offset = self.findFreeSpace(needed_size, entry_size);
1118 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);
1119 if (amt != shdr.sh_size) return error.InputOutput;
1120 shdr.sh_offset = new_offset;
1121 phdr.p_offset = new_offset;
1122 }
1123 shdr.sh_size = needed_size;
1124 phdr.p_memsz = needed_size;
1125 phdr.p_filesz = needed_size;
1126
1127 self.shdr_table_dirty = true; // TODO look into making only the one section dirty
1128 self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
1129
1130 self.fn_trampoline_table_count_dirty = false;
1131 }
1132 const off = shdr.sh_offset + @as(u64, entry_size) * index;
1133 const vaddr = @intCast(u32, self.fn_trampoline_table.items[index]);
1134 codegen.writePltEntry(self.options.target, &entry_buf, vaddr);
1135 try self.file.?.pwriteAll(entry_buf[0..entry_size], off);
1136 }
1137
1020 fn writeOffsetTableEntry(self: *ElfFile, index: usize) !void {1138 fn writeOffsetTableEntry(self: *ElfFile, index: usize) !void {
1021 const shdr = &self.sections.items[self.got_section_index.?];1139 const shdr = &self.sections.items[self.got_section_index.?];
1022 const phdr = &self.program_headers.items[self.phdr_got_index.?];1140 const phdr = &self.program_headers.items[self.phdr_got_index.?];
...@@ -1034,6 +1152,7 @@ pub const ElfFile = struct {...@@ -1034,6 +1152,7 @@ pub const ElfFile = struct {
1034 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);1152 const amt = try self.file.?.copyRangeAll(shdr.sh_offset, self.file.?, new_offset, shdr.sh_size);
1035 if (amt != shdr.sh_size) return error.InputOutput;1153 if (amt != shdr.sh_size) return error.InputOutput;
1036 shdr.sh_offset = new_offset;1154 shdr.sh_offset = new_offset;
1155 phdr.p_offset = new_offset;
1037 }1156 }
1038 shdr.sh_size = needed_size;1157 shdr.sh_size = needed_size;
1039 phdr.p_memsz = needed_size;1158 phdr.p_memsz = needed_size;