| author | |
| committer | |
| log | 6c731be3a1710f3c70a955624c30467616f1d1c0 |
| tree | c5c263743d1dd630977ea07903a89a89bb76259b |
| parent | b2fad5c58bfe2c8b013a5720c509b792e227415c |
5 files changed, 105 insertions(+), 68 deletions(-)
src/link/Elf.zig+16-51| ... | ... | @@ -1282,7 +1282,6 @@ pub fn flushModule(self: *Elf, arena: Allocator, tid: Zcu.PerThread.Id, prog_nod |
| 1282 | 1282 | try self.addCommentString(); |
| 1283 | 1283 | try self.finalizeMergeSections(); |
| 1284 | 1284 | try self.initOutputSections(); |
| 1285 | try self.initMergeSections(); | |
| 1286 | 1285 | if (self.linkerDefinedPtr()) |obj| { |
| 1287 | 1286 | try obj.initStartStopSymbols(self); |
| 1288 | 1287 | } |
| ... | ... | @@ -3048,17 +3047,17 @@ pub fn finalizeMergeSections(self: *Elf) !void { |
| 3048 | 3047 | } |
| 3049 | 3048 | |
| 3050 | 3049 | pub fn updateMergeSectionSizes(self: *Elf) !void { |
| 3050 | for (self.merge_sections.items) |*msec| { | |
| 3051 | msec.updateSize(); | |
| 3052 | } | |
| 3051 | 3053 | for (self.merge_sections.items) |*msec| { |
| 3052 | 3054 | const shdr = &self.shdrs.items[msec.output_section_index]; |
| 3053 | for (msec.finalized_subsections.items) |msub_index| { | |
| 3054 | const msub = msec.mergeSubsection(msub_index); | |
| 3055 | assert(msub.alive); | |
| 3056 | const offset = msub.alignment.forward(shdr.sh_size); | |
| 3057 | const padding = offset - shdr.sh_size; | |
| 3058 | msub.value = @intCast(offset); | |
| 3059 | shdr.sh_size += padding + msub.size; | |
| 3060 | shdr.sh_addralign = @max(shdr.sh_addralign, msub.alignment.toByteUnits() orelse 1); | |
| 3061 | } | |
| 3055 | const offset = msec.alignment.forward(shdr.sh_size); | |
| 3056 | const padding = offset - shdr.sh_size; | |
| 3057 | msec.value = @intCast(offset); | |
| 3058 | shdr.sh_size += padding + msec.size; | |
| 3059 | shdr.sh_addralign = @max(shdr.sh_addralign, msec.alignment.toByteUnits() orelse 1); | |
| 3060 | shdr.sh_entsize = if (shdr.sh_entsize == 0) msec.entsize else @min(shdr.sh_entsize, msec.entsize); | |
| 3062 | 3061 | } |
| 3063 | 3062 | } |
| 3064 | 3063 | |
| ... | ... | @@ -3069,7 +3068,8 @@ pub fn writeMergeSections(self: *Elf) !void { |
| 3069 | 3068 | |
| 3070 | 3069 | for (self.merge_sections.items) |*msec| { |
| 3071 | 3070 | const shdr = self.shdrs.items[msec.output_section_index]; |
| 3072 | const size = math.cast(usize, shdr.sh_size) orelse return error.Overflow; | |
| 3071 | const fileoff = math.cast(usize, msec.value + shdr.sh_offset) orelse return error.Overflow; | |
| 3072 | const size = math.cast(usize, msec.size) orelse return error.Overflow; | |
| 3073 | 3073 | try buffer.ensureTotalCapacity(size); |
| 3074 | 3074 | buffer.appendNTimesAssumeCapacity(0, size); |
| 3075 | 3075 | |
| ... | ... | @@ -3081,7 +3081,7 @@ pub fn writeMergeSections(self: *Elf) !void { |
| 3081 | 3081 | @memcpy(buffer.items[off..][0..string.len], string); |
| 3082 | 3082 | } |
| 3083 | 3083 | |
| 3084 | try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset); | |
| 3084 | try self.base.file.?.pwriteAll(buffer.items, fileoff); | |
| 3085 | 3085 | buffer.clearRetainingCapacity(); |
| 3086 | 3086 | } |
| 3087 | 3087 | } |
| ... | ... | @@ -3090,26 +3090,9 @@ fn initOutputSections(self: *Elf) !void { |
| 3090 | 3090 | for (self.objects.items) |index| { |
| 3091 | 3091 | try self.file(index).?.object.initOutputSections(self); |
| 3092 | 3092 | } |
| 3093 | } | |
| 3094 | ||
| 3095 | pub fn initMergeSections(self: *Elf) !void { | |
| 3096 | 3093 | for (self.merge_sections.items) |*msec| { |
| 3097 | 3094 | if (msec.finalized_subsections.items.len == 0) continue; |
| 3098 | const name = msec.name(self); | |
| 3099 | const shndx = self.sectionByName(name) orelse try self.addSection(.{ | |
| 3100 | .name = msec.name_offset, | |
| 3101 | .type = msec.type, | |
| 3102 | .flags = msec.flags, | |
| 3103 | }); | |
| 3104 | msec.output_section_index = shndx; | |
| 3105 | ||
| 3106 | var entsize = msec.mergeSubsection(msec.finalized_subsections.items[0]).entsize; | |
| 3107 | for (msec.finalized_subsections.items) |msub_index| { | |
| 3108 | const msub = msec.mergeSubsection(msub_index); | |
| 3109 | entsize = @min(entsize, msub.entsize); | |
| 3110 | } | |
| 3111 | const shdr = &self.shdrs.items[shndx]; | |
| 3112 | shdr.sh_entsize = entsize; | |
| 3095 | try msec.initOutputSection(self); | |
| 3113 | 3096 | } |
| 3114 | 3097 | } |
| 3115 | 3098 | |
| ... | ... | @@ -4427,7 +4410,6 @@ pub fn updateSymtabSize(self: *Elf) !void { |
| 4427 | 4410 | if (self.eh_frame_section_index) |_| { |
| 4428 | 4411 | nlocals += 1; |
| 4429 | 4412 | } |
| 4430 | nlocals += @intCast(self.merge_sections.items.len); | |
| 4431 | 4413 | |
| 4432 | 4414 | if (self.requiresThunks()) for (self.thunks.items) |*th| { |
| 4433 | 4415 | th.output_symtab_ctx.ilocal = nlocals + 1; |
| ... | ... | @@ -4751,30 +4733,12 @@ fn writeSectionSymbols(self: *Elf) void { |
| 4751 | 4733 | }; |
| 4752 | 4734 | ilocal += 1; |
| 4753 | 4735 | } |
| 4754 | ||
| 4755 | for (self.merge_sections.items) |msec| { | |
| 4756 | const shdr = self.shdrs.items[msec.output_section_index]; | |
| 4757 | const out_sym = &self.symtab.items[ilocal]; | |
| 4758 | out_sym.* = .{ | |
| 4759 | .st_name = 0, | |
| 4760 | .st_value = shdr.sh_addr, | |
| 4761 | .st_info = elf.STT_SECTION, | |
| 4762 | .st_shndx = @intCast(msec.output_section_index), | |
| 4763 | .st_size = 0, | |
| 4764 | .st_other = 0, | |
| 4765 | }; | |
| 4766 | ilocal += 1; | |
| 4767 | } | |
| 4768 | 4736 | } |
| 4769 | 4737 | |
| 4770 | 4738 | pub fn sectionSymbolOutputSymtabIndex(self: Elf, shndx: u32) u32 { |
| 4771 | 4739 | if (self.eh_frame_section_index) |index| { |
| 4772 | 4740 | if (index == shndx) return @intCast(self.output_sections.keys().len + 1); |
| 4773 | 4741 | } |
| 4774 | const base: usize = if (self.eh_frame_section_index == null) 0 else 1; | |
| 4775 | for (self.merge_sections.items, 0..) |msec, index| { | |
| 4776 | if (msec.output_section_index == shndx) return @intCast(self.output_sections.keys().len + 1 + index + base); | |
| 4777 | } | |
| 4778 | 4742 | return @intCast(self.output_sections.getIndex(shndx).? + 1); |
| 4779 | 4743 | } |
| 4780 | 4744 | |
| ... | ... | @@ -5537,10 +5501,11 @@ fn formatShdr( |
| 5537 | 5501 | _ = options; |
| 5538 | 5502 | _ = unused_fmt_string; |
| 5539 | 5503 | const shdr = ctx.shdr; |
| 5540 | try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : flags({})", .{ | |
| 5504 | try writer.print("{s} : @{x} ({x}) : align({x}) : size({x}) : entsize({x}) : flags({})", .{ | |
| 5541 | 5505 | ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset, |
| 5542 | 5506 | shdr.sh_addr, shdr.sh_addralign, |
| 5543 | shdr.sh_size, fmtShdrFlags(shdr.sh_flags), | |
| 5507 | shdr.sh_size, shdr.sh_entsize, | |
| 5508 | fmtShdrFlags(shdr.sh_flags), | |
| 5544 | 5509 | }); |
| 5545 | 5510 | } |
| 5546 | 5511 |
src/link/Elf/ZigObject.zig+7-13| ... | ... | @@ -183,6 +183,7 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi |
| 183 | 183 | try dwarf.resolveRelocs(); |
| 184 | 184 | |
| 185 | 185 | const gpa = elf_file.base.comp.gpa; |
| 186 | const cpu_arch = elf_file.getTarget().cpu.arch; | |
| 186 | 187 | |
| 187 | 188 | // TODO invert this logic so that we manage the output section with the atom, not the |
| 188 | 189 | // other way around |
| ... | ... | @@ -242,20 +243,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi |
| 242 | 243 | target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off |
| 243 | 244 | else |
| 244 | 245 | 0)); |
| 245 | const r_type: elf.R_X86_64 = switch (dwarf.format) { | |
| 246 | .@"32" => .@"32", | |
| 247 | .@"64" => .@"64", | |
| 248 | }; | |
| 246 | const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch); | |
| 249 | 247 | log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{ |
| 250 | 248 | self.symbol(target_sym_index).name(elf_file), |
| 251 | 249 | r_offset, |
| 252 | 250 | r_addend, |
| 253 | relocation.fmtRelocType(@intFromEnum(r_type), elf_file.getTarget().cpu.arch), | |
| 251 | relocation.fmtRelocType(r_type, cpu_arch), | |
| 254 | 252 | }); |
| 255 | 253 | atom_ptr.addRelocAssumeCapacity(.{ |
| 256 | 254 | .r_offset = r_offset, |
| 257 | 255 | .r_addend = r_addend, |
| 258 | .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | @intFromEnum(r_type), | |
| 256 | .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | r_type, | |
| 259 | 257 | }, self); |
| 260 | 258 | } |
| 261 | 259 | |
| ... | ... | @@ -264,21 +262,17 @@ pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !voi |
| 264 | 262 | const target_sym = self.symbol(reloc.target_sym); |
| 265 | 263 | const r_offset = unit.off + unit.header_len + unit.getEntry(reloc.source_entry).off + reloc.source_off; |
| 266 | 264 | const r_addend: i64 = @intCast(reloc.target_off); |
| 267 | const r_type: elf.R_X86_64 = switch (dwarf.address_size) { | |
| 268 | .@"32" => if (target_sym.flags.is_tls) .DTPOFF32 else .@"32", | |
| 269 | .@"64" => if (target_sym.flags.is_tls) .DTPOFF64 else .@"64", | |
| 270 | else => unreachable, | |
| 271 | }; | |
| 265 | const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch); | |
| 272 | 266 | log.debug(" {s} <- r_off={x}, r_add={x}, r_type={}", .{ |
| 273 | 267 | target_sym.name(elf_file), |
| 274 | 268 | r_offset, |
| 275 | 269 | r_addend, |
| 276 | relocation.fmtRelocType(@intFromEnum(r_type), elf_file.getTarget().cpu.arch), | |
| 270 | relocation.fmtRelocType(r_type, cpu_arch), | |
| 277 | 271 | }); |
| 278 | 272 | atom_ptr.addRelocAssumeCapacity(.{ |
| 279 | 273 | .r_offset = r_offset, |
| 280 | 274 | .r_addend = r_addend, |
| 281 | .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | @intFromEnum(r_type), | |
| 275 | .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | r_type, | |
| 282 | 276 | }, self); |
| 283 | 277 | } |
| 284 | 278 | } |
src/link/Elf/merge_section.zig+32-2| ... | ... | @@ -1,4 +1,8 @@ |
| 1 | 1 | pub const MergeSection = struct { |
| 2 | value: u64 = 0, | |
| 3 | size: u64 = 0, | |
| 4 | alignment: Atom.Alignment = .@"1", | |
| 5 | entsize: u32 = 0, | |
| 2 | 6 | name_offset: u32 = 0, |
| 3 | 7 | type: u32 = 0, |
| 4 | 8 | flags: u64 = 0, |
| ... | ... | @@ -26,7 +30,7 @@ pub const MergeSection = struct { |
| 26 | 30 | |
| 27 | 31 | pub fn address(msec: MergeSection, elf_file: *Elf) i64 { |
| 28 | 32 | const shdr = elf_file.shdrs.items[msec.output_section_index]; |
| 29 | return @intCast(shdr.sh_addr); | |
| 33 | return @intCast(shdr.sh_addr + msec.value); | |
| 30 | 34 | } |
| 31 | 35 | |
| 32 | 36 | const InsertResult = struct { |
| ... | ... | @@ -90,6 +94,29 @@ pub const MergeSection = struct { |
| 90 | 94 | std.mem.sort(MergeSubsection.Index, msec.finalized_subsections.items, msec, sortFn); |
| 91 | 95 | } |
| 92 | 96 | |
| 97 | pub fn updateSize(msec: *MergeSection) void { | |
| 98 | for (msec.finalized_subsections.items) |msub_index| { | |
| 99 | const msub = msec.mergeSubsection(msub_index); | |
| 100 | assert(msub.alive); | |
| 101 | const offset = msub.alignment.forward(msec.size); | |
| 102 | const padding = offset - msec.size; | |
| 103 | msub.value = @intCast(offset); | |
| 104 | msec.size += padding + msub.size; | |
| 105 | msec.alignment = msec.alignment.max(msub.alignment); | |
| 106 | msec.entsize = if (msec.entsize == 0) msub.entsize else @min(msec.entsize, msub.entsize); | |
| 107 | } | |
| 108 | } | |
| 109 | ||
| 110 | pub fn initOutputSection(msec: *MergeSection, elf_file: *Elf) !void { | |
| 111 | const shndx = elf_file.sectionByName(msec.name(elf_file)) orelse try elf_file.addSection(.{ | |
| 112 | .name = msec.name_offset, | |
| 113 | .type = msec.type, | |
| 114 | .flags = msec.flags, | |
| 115 | }); | |
| 116 | try elf_file.output_sections.put(elf_file.base.comp.gpa, shndx, .{}); | |
| 117 | msec.output_section_index = shndx; | |
| 118 | } | |
| 119 | ||
| 93 | 120 | pub fn addMergeSubsection(msec: *MergeSection, allocator: Allocator) !MergeSubsection.Index { |
| 94 | 121 | const index: MergeSubsection.Index = @intCast(msec.subsections.items.len); |
| 95 | 122 | const msub = try msec.subsections.addOne(allocator); |
| ... | ... | @@ -163,9 +190,12 @@ pub const MergeSection = struct { |
| 163 | 190 | _ = unused_fmt_string; |
| 164 | 191 | const msec = ctx.msec; |
| 165 | 192 | const elf_file = ctx.elf_file; |
| 166 | try writer.print("{s} : @{x} : type({x}) : flags({x})\n", .{ | |
| 193 | try writer.print("{s} : @{x} : size({x}) : align({x}) : entsize({x}) : type({x}) : flags({x})\n", .{ | |
| 167 | 194 | msec.name(elf_file), |
| 168 | 195 | msec.address(elf_file), |
| 196 | msec.size, | |
| 197 | msec.alignment.toByteUnits() orelse 0, | |
| 198 | msec.entsize, | |
| 169 | 199 | msec.type, |
| 170 | 200 | msec.flags, |
| 171 | 201 | }); |
src/link/Elf/relocatable.zig+10-2| ... | ... | @@ -42,7 +42,11 @@ pub fn flushStaticLib(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]co |
| 42 | 42 | try elf_file.finalizeMergeSections(); |
| 43 | 43 | zig_object.claimUnresolvedObject(elf_file); |
| 44 | 44 | |
| 45 | try elf_file.initMergeSections(); | |
| 45 | for (elf_file.merge_sections.items) |*msec| { | |
| 46 | if (msec.finalized_subsections.items.len == 0) continue; | |
| 47 | try msec.initOutputSection(elf_file); | |
| 48 | } | |
| 49 | ||
| 46 | 50 | try elf_file.initSymtab(); |
| 47 | 51 | try elf_file.initShStrtab(); |
| 48 | 52 | try elf_file.sortShdrs(); |
| ... | ... | @@ -198,7 +202,6 @@ pub fn flushObject(elf_file: *Elf, comp: *Compilation, module_obj_path: ?[]const |
| 198 | 202 | claimUnresolved(elf_file); |
| 199 | 203 | |
| 200 | 204 | try initSections(elf_file); |
| 201 | try elf_file.initMergeSections(); | |
| 202 | 205 | try elf_file.sortShdrs(); |
| 203 | 206 | if (elf_file.zigObjectPtr()) |zig_object| { |
| 204 | 207 | try zig_object.addAtomsToRelaSections(elf_file); |
| ... | ... | @@ -294,6 +297,11 @@ fn initSections(elf_file: *Elf) !void { |
| 294 | 297 | try object.initRelaSections(elf_file); |
| 295 | 298 | } |
| 296 | 299 | |
| 300 | for (elf_file.merge_sections.items) |*msec| { | |
| 301 | if (msec.finalized_subsections.items.len == 0) continue; | |
| 302 | try msec.initOutputSection(elf_file); | |
| 303 | } | |
| 304 | ||
| 297 | 305 | const needs_eh_frame = for (elf_file.objects.items) |index| { |
| 298 | 306 | if (elf_file.file(index).?.object.cies.items.len > 0) break true; |
| 299 | 307 | } else false; |
src/link/Elf/relocation.zig+40| ... | ... | @@ -91,6 +91,44 @@ pub fn encode(comptime kind: Kind, cpu_arch: std.Target.Cpu.Arch) u32 { |
| 91 | 91 | }; |
| 92 | 92 | } |
| 93 | 93 | |
| 94 | pub const dwarf = struct { | |
| 95 | pub fn crossSectionRelocType(format: DW.Format, cpu_arch: std.Target.Cpu.Arch) u32 { | |
| 96 | return switch (cpu_arch) { | |
| 97 | .x86_64 => @intFromEnum(switch (format) { | |
| 98 | .@"32" => elf.R_X86_64.@"32", | |
| 99 | .@"64" => .@"64", | |
| 100 | }), | |
| 101 | .riscv64 => @intFromEnum(switch (format) { | |
| 102 | .@"32" => elf.R_RISCV.@"32", | |
| 103 | .@"64" => .@"64", | |
| 104 | }), | |
| 105 | else => @panic("TODO unhandled cpu arch"), | |
| 106 | }; | |
| 107 | } | |
| 108 | ||
| 109 | pub fn externalRelocType( | |
| 110 | target: Symbol, | |
| 111 | address_size: Dwarf.AddressSize, | |
| 112 | cpu_arch: std.Target.Cpu.Arch, | |
| 113 | ) u32 { | |
| 114 | return switch (cpu_arch) { | |
| 115 | .x86_64 => @intFromEnum(switch (address_size) { | |
| 116 | .@"32" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF32 else .@"32", | |
| 117 | .@"64" => if (target.flags.is_tls) elf.R_X86_64.DTPOFF64 else .@"64", | |
| 118 | else => unreachable, | |
| 119 | }), | |
| 120 | .riscv64 => @intFromEnum(switch (address_size) { | |
| 121 | .@"32" => elf.R_RISCV.@"32", | |
| 122 | .@"64" => elf.R_RISCV.@"64", | |
| 123 | else => unreachable, | |
| 124 | }), | |
| 125 | else => @panic("TODO unhandled cpu arch"), | |
| 126 | }; | |
| 127 | } | |
| 128 | ||
| 129 | const DW = std.dwarf; | |
| 130 | }; | |
| 131 | ||
| 94 | 132 | const FormatRelocTypeCtx = struct { |
| 95 | 133 | r_type: u32, |
| 96 | 134 | cpu_arch: std.Target.Cpu.Arch, |
| ... | ... | @@ -124,4 +162,6 @@ const assert = std.debug.assert; |
| 124 | 162 | const elf = std.elf; |
| 125 | 163 | const std = @import("std"); |
| 126 | 164 | |
| 165 | const Dwarf = @import("../Dwarf.zig"); | |
| 127 | 166 | const Elf = @import("../Elf.zig"); |
| 167 | const Symbol = @import("Symbol.zig"); |