| ... | @@ -246,6 +246,7 @@ changed_symtab_index: std.array_hash_map.Auto(Symbol.Global.Index, void), | ... | @@ -246,6 +246,7 @@ changed_symtab_index: std.array_hash_map.Auto(Symbol.Global.Index, void), |
| 246 | /// entry in the `.dynamic` section. This allows adding `DT_TEXTREL` to the output `.dynamic` | 246 | /// entry in the `.dynamic` section. This allows adding `DT_TEXTREL` to the output `.dynamic` |
| 247 | /// section in `flush` only when it is actually necessary. See also `nodeAllowsDynamicReloc`. | 247 | /// section in `flush` only when it is actually necessary. See also `nodeAllowsDynamicReloc`. |
| 248 | textrel_count: u32, | 248 | textrel_count: u32, |
| | 249 | entry_gsi: Symbol.Global.Index.Optional, |
| 249 | | 250 | |
| 250 | dwarf: Dwarf, | 251 | dwarf: Dwarf, |
| 251 | dwarf_shared: std.enums.EnumArray(Dwarf.SharedSection, dwarf_relocs.Shared), | 252 | dwarf_shared: std.enums.EnumArray(Dwarf.SharedSection, dwarf_relocs.Shared), |
| ... | @@ -3073,6 +3074,8 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{ | ... | @@ -3073,6 +3074,8 @@ fn addGlobalSymbol(elf: *Elf, opts: Symbol.Global.AddOptions) (error{ |
| 3073 | } || Error)!Symbol.Global.Index { | 3074 | } || Error)!Symbol.Global.Index { |
| 3074 | _ = opts.lib_name; // TODO | 3075 | _ = opts.lib_name; // TODO |
| 3075 | | 3076 | |
| | 3077 | log.debug("addGlobalSymbol({q})", .{opts.name}); |
| | 3078 | |
| 3076 | const gpa = elf.base.comp.gpa; | 3079 | const gpa = elf.base.comp.gpa; |
| 3077 | | 3080 | |
| 3078 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 3081 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -5138,6 +5141,7 @@ fn create( | ... | @@ -5138,6 +5141,7 @@ fn create( |
| 5138 | .section_by_name = .empty, | 5141 | .section_by_name = .empty, |
| 5139 | .changed_symtab_index = .empty, | 5142 | .changed_symtab_index = .empty, |
| 5140 | .textrel_count = 0, | 5143 | .textrel_count = 0, |
| | 5144 | .entry_gsi = undefined, |
| 5141 | | 5145 | |
| 5142 | .dwarf = .init(&elf.base, switch (comp.config.debug_format) { | 5146 | .dwarf = .init(&elf.base, switch (comp.config.debug_format) { |
| 5143 | .strip => .@"32", // for .eh_frame | 5147 | .strip => .@"32", // for .eh_frame |
| ... | @@ -6561,6 +6565,31 @@ fn initHeaders( | ... | @@ -6561,6 +6565,31 @@ fn initHeaders( |
| 6561 | .code_view => unreachable, | 6565 | .code_view => unreachable, |
| 6562 | } | 6566 | } |
| 6563 | | 6567 | |
| | 6568 | // If we have an entry point symbol, create the undefined reference now. |
| | 6569 | elf.entry_gsi = entry: switch (elf.options.entry) { |
| | 6570 | .default => switch (comp.config.output_mode) { |
| | 6571 | .Exe => continue :entry .enabled, |
| | 6572 | .Lib, .Obj => continue :entry .disabled, |
| | 6573 | }, |
| | 6574 | .enabled => continue :entry .{ .named = "_start" }, |
| | 6575 | .disabled => .none, |
| | 6576 | .named => |sym_name| .wrap(elf.addGlobalSymbol(.{ |
| | 6577 | .node = .none, |
| | 6578 | .name = sym_name, |
| | 6579 | .value = 0, |
| | 6580 | .size = 0, |
| | 6581 | .type = .NOTYPE, |
| | 6582 | .bind = .strong, |
| | 6583 | .visibility = .DEFAULT, |
| | 6584 | .shndx = .UNDEF, |
| | 6585 | }) catch |err| switch (err) { |
| | 6586 | error.MultipleDefinitions => unreachable, // shndx is undef |
| | 6587 | error.MultipleDefaultVersions => unreachable, // not a versioned symbol |
| | 6588 | error.UndefinedDefaultVersion => unreachable, // not a versioned symbol |
| | 6589 | else => |e| return e, |
| | 6590 | }), |
| | 6591 | }; |
| | 6592 | |
| 6564 | assert(elf.nodes.len == expected_nodes_len); | 6593 | assert(elf.nodes.len == expected_nodes_len); |
| 6565 | assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF | 6594 | assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF |
| 6566 | | 6595 | |
| ... | @@ -10884,20 +10913,22 @@ fn flushInner( | ... | @@ -10884,20 +10913,22 @@ fn flushInner( |
| 10884 | elf.flushDynamic(); | 10913 | elf.flushDynamic(); |
| 10885 | | 10914 | |
| 10886 | const entry_addr: u64 = entry: { | 10915 | const entry_addr: u64 = entry: { |
| 10887 | const sym_name: []const u8 = name: switch (elf.options.entry) { | 10916 | const entry_gsi = elf.entry_gsi.unwrap() orelse break :entry 0; |
| 10888 | .default => switch (comp.config.output_mode) { | 10917 | |
| 10889 | .Exe => continue :name .enabled, | 10918 | // Even though we already reported undefined globals earlier, we also need to check here |
| 10890 | .Lib, .Obj => continue :name .disabled, | 10919 | // whether the entry point is defined. There are two reasons for this: |
| 10891 | }, | 10920 | // |
| 10892 | .disabled => break :entry 0, | 10921 | // * If we are emitting something other than an executable, we skipped the undefined globals |
| 10893 | .enabled => "_start", | 10922 | // check, but there could still be an entry point (e.g. due to `-fentry=foo` on the CLI). |
| 10894 | .named => |named| named, | 10923 | // |
| 10895 | }; | 10924 | // * The entry point might be defined in an input DSO, which would satisfy the undefined |
| 10896 | const gsi = elf.globalByName(.{ | 10925 | // symbol reference but is insufficient here: the entry point needs a local definition. |
| 10897 | .name = sym_name, | 10926 | |
| 10898 | .version = null, | 10927 | if (!entry_gsi.resolveAlias(elf).defined(elf)) { |
| 10899 | }) orelse break :entry 0; | 10928 | return diags.fail("undefined entry point symbol '{s}'", .{entry_gsi.name(elf)}); |
| 10900 | break :entry Symbol.Id.global(gsi).value(elf); | 10929 | } |
| | 10930 | |
| | 10931 | break :entry Symbol.Id.global(entry_gsi).value(elf); |
| 10901 | }; | 10932 | }; |
| 10902 | switch (elf.ehdrPtr()) { | 10933 | switch (elf.ehdrPtr()) { |
| 10903 | inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(entry_addr)), | 10934 | inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(entry_addr)), |