authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-26 23:05:32+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-08-29 11:39:35+02:00
log84853c5c56e87a7ee6c5392756b0773b650d283c
tree0928d4946b4130fc31f2603a2cb575be3df1e45f
parent7f6973fbae3b01827a71497f647ee27e64845f51

macho: unify resolving globals


1 files changed, 77 insertions(+), 70 deletions(-)

src/link/MachO/zld.zig+77-70
...@@ -245,6 +245,82 @@ pub const Zld = struct {...@@ -245,6 +245,82 @@ pub const Zld = struct {
245 try self.resolveSymbolsAtLoading();245 try self.resolveSymbolsAtLoading();
246 }246 }
247247
248 fn resolveGlobalSymbol(self: *Zld, current: SymbolWithLoc) !void {
249 const gpa = self.gpa;
250 const sym = self.getSymbol(current);
251 const sym_name = self.getSymbolName(current);
252
253 const gop = try self.getOrPutGlobalPtr(sym_name);
254 if (!gop.found_existing) {
255 gop.value_ptr.* = current;
256 if (sym.undf() and !sym.tentative()) {
257 try self.unresolved.putNoClobber(gpa, self.getGlobalIndex(sym_name).?, {});
258 }
259 return;
260 }
261 const global_index = self.getGlobalIndex(sym_name).?;
262 const global = gop.value_ptr.*;
263 const global_sym = self.getSymbol(global);
264
265 // Cases to consider: sym vs global_sym
266 // 1. strong(sym) and strong(global_sym) => error
267 // 2. strong(sym) and weak(global_sym) => sym
268 // 3. strong(sym) and tentative(global_sym) => sym
269 // 4. strong(sym) and undf(global_sym) => sym
270 // 5. weak(sym) and strong(global_sym) => global_sym
271 // 6. weak(sym) and tentative(global_sym) => sym
272 // 7. weak(sym) and undf(global_sym) => sym
273 // 8. tentative(sym) and strong(global_sym) => global_sym
274 // 9. tentative(sym) and weak(global_sym) => global_sym
275 // 10. tentative(sym) and tentative(global_sym) => pick larger
276 // 11. tentative(sym) and undf(global_sym) => sym
277 // 12. undf(sym) and * => global_sym
278 //
279 // Reduces to:
280 // 1. strong(sym) and strong(global_sym) => error
281 // 2. * and strong(global_sym) => global_sym
282 // 3. weak(sym) and weak(global_sym) => global_sym
283 // 4. tentative(sym) and tentative(global_sym) => pick larger
284 // 5. undf(sym) and * => global_sym
285 // 6. else => sym
286
287 const sym_is_strong = sym.sect() and !(sym.weakDef() or sym.pext());
288 const global_is_strong = global_sym.sect() and !(global_sym.weakDef() or global_sym.pext());
289 const sym_is_weak = sym.sect() and (sym.weakDef() or sym.pext());
290 const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext());
291
292 if (sym_is_strong and global_is_strong) {
293 log.err("symbol '{s}' defined multiple times", .{sym_name});
294 if (global.getFile()) |file| {
295 log.err(" first definition in '{s}'", .{self.objects.items[file].name});
296 }
297 if (current.getFile()) |file| {
298 log.err(" next definition in '{s}'", .{self.objects.items[file].name});
299 }
300 return error.MultipleSymbolDefinitions;
301 }
302
303 if (current.getFile()) |file| {
304 const object = &self.objects.items[file];
305 object.globals_lookup[current.sym_index] = global_index;
306 }
307
308 if (global_is_strong) return;
309 if (sym_is_weak and global_is_weak) return;
310 if (sym.tentative() and global_sym.tentative()) {
311 if (global_sym.n_value >= sym.n_value) return;
312 }
313 if (sym.undf() and !sym.tentative()) return;
314
315 if (global.getFile()) |file| {
316 const global_object = &self.objects.items[file];
317 global_object.globals_lookup[global.sym_index] = global_index;
318 }
319 _ = self.unresolved.swapRemove(global_index);
320
321 gop.value_ptr.* = current;
322 }
323
248 fn resolveSymbolsInObject(self: *Zld, object_id: u32) !void {324 fn resolveSymbolsInObject(self: *Zld, object_id: u32) !void {
249 const object = &self.objects.items[object_id];325 const object = &self.objects.items[object_id];
250 const in_symtab = object.in_symtab orelse return;326 const in_symtab = object.in_symtab orelse return;
...@@ -285,76 +361,7 @@ pub const Zld = struct {...@@ -285,76 +361,7 @@ pub const Zld = struct {
285 continue;361 continue;
286 }362 }
287363
288 const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = object_id + 1 };364 try self.resolveGlobalSymbol(.{ .sym_index = sym_index, .file = object_id + 1 });
289
290 const gop = try self.getOrPutGlobalPtr(sym_name);
291 if (!gop.found_existing) {
292 gop.value_ptr.* = sym_loc;
293 if (sym.undf() and !sym.tentative()) {
294 try self.unresolved.putNoClobber(self.gpa, self.getGlobalIndex(sym_name).?, {});
295 }
296 continue;
297 }
298 const global_index = self.getGlobalIndex(sym_name).?;
299 const global = gop.value_ptr;
300 const global_sym = self.getSymbol(global.*);
301
302 // Cases to consider: sym vs global_sym
303 // 1. strong(sym) and strong(global_sym) => error
304 // 2. strong(sym) and weak(global_sym) => sym
305 // 3. strong(sym) and tentative(global_sym) => sym
306 // 4. strong(sym) and undf(global_sym) => sym
307 // 5. weak(sym) and strong(global_sym) => global_sym
308 // 6. weak(sym) and tentative(global_sym) => sym
309 // 7. weak(sym) and undf(global_sym) => sym
310 // 8. tentative(sym) and strong(global_sym) => global_sym
311 // 9. tentative(sym) and weak(global_sym) => global_sym
312 // 10. tentative(sym) and tentative(global_sym) => pick larger
313 // 11. tentative(sym) and undf(global_sym) => sym
314 // 12. undf(sym) and * => global_sym
315 //
316 // Reduces to:
317 // 1. strong(sym) and strong(global_sym) => error
318 // 2. * and strong(global_sym) => global_sym
319 // 3. weak(sym) and weak(global_sym) => global_sym
320 // 4. tentative(sym) and tentative(global_sym) => pick larger
321 // 5. undf(sym) and * => global_sym
322 // 6. else => sym
323
324 const sym_is_strong = sym.sect() and !(sym.weakDef() or sym.pext());
325 const global_is_strong = global_sym.sect() and !(global_sym.weakDef() or global_sym.pext());
326 const sym_is_weak = sym.sect() and (sym.weakDef() or sym.pext());
327 const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext());
328
329 if (sym_is_strong and global_is_strong) {
330 log.err("symbol '{s}' defined multiple times", .{sym_name});
331 if (global.getFile()) |file| {
332 log.err(" first definition in '{s}'", .{self.objects.items[file].name});
333 }
334 log.err(" next definition in '{s}'", .{self.objects.items[object_id].name});
335 return error.MultipleSymbolDefinitions;
336 }
337
338 const update_global = blk: {
339 if (global_is_strong) break :blk false;
340 if (sym_is_weak and global_is_weak) break :blk false;
341 if (sym.tentative() and global_sym.tentative()) {
342 if (global_sym.n_value >= sym.n_value) break :blk false;
343 }
344 if (sym.undf() and !sym.tentative()) break :blk false;
345 break :blk true;
346 };
347
348 if (update_global) {
349 if (global.getFile()) |file| {
350 const global_object = &self.objects.items[file];
351 global_object.globals_lookup[global.sym_index] = global_index;
352 }
353 _ = self.unresolved.swapRemove(global_index);
354 global.* = sym_loc;
355 } else {
356 object.globals_lookup[sym_index] = global_index;
357 }
358 }365 }
359 }366 }
360367