zld: fix incorrectly worked out section size

Also, add a solution to a degenerate case where on x86_64 a relocation
refers to a cell in a section via section start address even though
a symbol exists. In such case, make the section spawned symbol an alias
of the actual symbol.
This commit is contained in:
Jakub Konka 2021-07-12 23:56:36 +02:00
parent de30a704b1
commit e17f12dd64
3 changed files with 41 additions and 34 deletions

View File

@ -431,29 +431,26 @@ const TextBlockParser = struct {
else
max_align;
const alias_only_indices = if (aliases.items.len > 0) blk: {
var out = std.ArrayList(u32).init(self.allocator);
try out.ensureTotalCapacity(aliases.items.len);
const block = try self.allocator.create(TextBlock);
errdefer self.allocator.destroy(block);
block.* = TextBlock.init(self.allocator);
block.local_sym_index = senior_nlist.index;
block.code = try self.allocator.dupe(u8, code);
block.size = size;
block.alignment = actual_align;
if (aliases.items.len > 0) {
try block.aliases.ensureTotalCapacity(aliases.items.len);
for (aliases.items) |alias| {
out.appendAssumeCapacity(alias.index);
block.aliases.appendAssumeCapacity(alias.index);
const sym = self.zld.locals.items[alias.index];
const reg = &sym.payload.regular;
reg.segment_id = self.match.seg;
reg.section_id = self.match.sect;
}
break :blk out.toOwnedSlice();
} else null;
const block = try self.allocator.create(TextBlock);
errdefer self.allocator.destroy(block);
block.* = TextBlock.init(self.allocator);
block.local_sym_index = senior_nlist.index;
block.aliases = alias_only_indices;
block.code = try self.allocator.dupe(u8, code);
block.size = size;
block.alignment = actual_align;
}
const relocs = filterRelocs(self.relocs, start_addr, end_addr);
if (relocs.len > 0) {
@ -617,7 +614,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
const tsect = &tseg.sections.items[match.sect];
const new_alignment = math.max(tsect.@"align", block.alignment);
const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2);
const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
tsect.size = new_size;
tsect.@"align" = new_alignment;
@ -653,6 +650,19 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
}
}
if (reg.address == sect.addr) {
if (self.sections_as_symbols.get(sect_id)) |alias| {
// Add alias.
const local_sym_index = @intCast(u32, zld.locals.items.len);
const reg_alias = &alias.payload.regular;
reg_alias.segment_id = match.seg;
reg_alias.section_id = match.sect;
reg_alias.local_sym_index = local_sym_index;
try block.aliases.append(local_sym_index);
try zld.locals.append(zld.allocator, alias);
}
}
// Update target section's metadata
// TODO should we update segment's size here too?
// How does it tie with incremental space allocs?
@ -660,7 +670,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
const tsect = &tseg.sections.items[match.sect];
const new_alignment = math.max(tsect.@"align", block.alignment);
const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2);
const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
tsect.size = new_size;
tsect.@"align" = new_alignment;
@ -764,7 +774,7 @@ pub fn parseTextBlocks(self: *Object, zld: *Zld) !void {
const tsect = &tseg.sections.items[match.sect];
const new_alignment = math.max(tsect.@"align", block.alignment);
const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2);
const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
tsect.size = new_size;
tsect.@"align" = new_alignment;

View File

@ -125,7 +125,7 @@ pub const Output = struct {
pub const TextBlock = struct {
allocator: *Allocator,
local_sym_index: u32,
aliases: ?[]u32 = null,
aliases: std.ArrayList(u32),
references: std.AutoArrayHashMap(u32, void),
contained: ?[]SymbolAtOffset = null,
code: []u8,
@ -146,6 +146,7 @@ pub const TextBlock = struct {
return .{
.allocator = allocator,
.local_sym_index = undefined,
.aliases = std.ArrayList(u32).init(allocator),
.references = std.AutoArrayHashMap(u32, void).init(allocator),
.code = undefined,
.relocs = std.ArrayList(Relocation).init(allocator),
@ -157,9 +158,7 @@ pub const TextBlock = struct {
}
pub fn deinit(self: *TextBlock) void {
if (self.aliases) |aliases| {
self.allocator.free(aliases);
}
self.aliases.deinit();
self.references.deinit();
if (self.contained) |contained| {
self.allocator.free(contained);
@ -179,9 +178,9 @@ pub const TextBlock = struct {
pub fn print_this(self: *const TextBlock, zld: *Zld) void {
log.warn("TextBlock", .{});
log.warn(" {}: {}", .{ self.local_sym_index, zld.locals.items[self.local_sym_index] });
if (self.aliases) |aliases| {
if (self.aliases.items.len > 0) {
log.warn(" aliases:", .{});
for (aliases) |index| {
for (self.aliases.items) |index| {
log.warn(" {}: {}", .{ index, zld.locals.items[index] });
}
}
@ -1082,12 +1081,10 @@ fn allocateTextBlocks(self: *Zld) !void {
});
// Update each alias (if any)
if (block.aliases) |aliases| {
for (aliases) |index| {
const alias_sym = self.locals.items[index];
assert(alias_sym.payload == .regular);
alias_sym.payload.regular.address = base_addr;
}
for (block.aliases.items) |index| {
const alias_sym = self.locals.items[index];
assert(alias_sym.payload == .regular);
alias_sym.payload.regular.address = base_addr;
}
// Update each symbol contained within the TextBlock
@ -1623,7 +1620,7 @@ fn resolveSymbols(self: *Zld) !void {
const tsect = &tseg.sections.items[match.sect];
const new_alignment = math.max(tsect.@"align", block.alignment);
const new_alignment_pow_2 = try math.powi(u32, 2, new_alignment);
const new_size = mem.alignForwardGeneric(u64, tsect.size + block.size, new_alignment_pow_2);
const new_size = mem.alignForwardGeneric(u64, tsect.size, new_alignment_pow_2) + block.size;
tsect.size = new_size;
tsect.@"align" = new_alignment;

View File

@ -878,9 +878,9 @@ pub const Parser = struct {
if (rel.r_extern == 0) {
const source_sym = self.zld.locals.items[self.block.local_sym_index].payload.regular;
const source_addr = source_sym.address + parsed.offset + @intCast(u32, addend) + 4;
const source_addr = source_sym.address + parsed.offset + 4;
const target_sym = parsed.target.payload.regular;
addend = @intCast(i64, source_addr) - @intCast(i64, target_sym.address);
addend = @intCast(i64, source_addr) + addend - @intCast(i64, target_sym.address);
}
parsed.payload = .{