| ... | ... | @@ -286,7 +286,11 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile, prog_node: std.Progre |
| 286 | 286 | .owner = undefined, |
| 287 | 287 | }; |
| 288 | 288 | }; |
| 289 | | var files = [_]Compilation.CSourceFile{ start_o, abi_note_o }; |
| 289 | const init_o: Compilation.CSourceFile = .{ |
| 290 | .src_path = try lib_path(comp, arena, lib_libc_glibc ++ "csu" ++ path.sep_str ++ "init.c"), |
| 291 | .owner = undefined, |
| 292 | }; |
| 293 | var files = [_]Compilation.CSourceFile{ start_o, abi_note_o, init_o }; |
| 290 | 294 | return comp.build_crt_file("Scrt1", .Obj, .@"glibc Scrt1.o", prog_node, &files); |
| 291 | 295 | }, |
| 292 | 296 | .libc_nonshared_a => { |
| ... | ... | @@ -682,6 +686,12 @@ pub const BuiltSharedObjects = struct { |
| 682 | 686 | |
| 683 | 687 | const all_map_basename = "all.map"; |
| 684 | 688 | |
| 689 | fn wordDirective(target: std.Target) []const u8 { |
| 690 | // Based on its description in the GNU `as` manual, you might assume that `.word` is sized |
| 691 | // according to the target word size. But no; that would just make too much sense. |
| 692 | return if (target.ptrBitWidth() == 64) ".quad" else ".long"; |
| 693 | } |
| 694 | |
| 685 | 695 | pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !void { |
| 686 | 696 | const tracy = trace(@src()); |
| 687 | 697 | defer tracy.end(); |
| ... | ... | @@ -923,6 +933,31 @@ pub fn buildSharedObjects(comp: *Compilation, prog_node: std.Progress.Node) !voi |
| 923 | 933 | |
| 924 | 934 | try stubs_asm.appendSlice(".data\n"); |
| 925 | 935 | |
| 936 | // For some targets, the real `libc.so.6` will contain a weak reference to `_IO_stdin_used`, |
| 937 | // making the linker put the symbol in the dynamic symbol table. We likewise need to emit a |
| 938 | // reference to it here for that effect, or it will not show up, which in turn will cause |
| 939 | // the real glibc to think that the program was built against an ancient `FILE` structure |
| 940 | // (pre-glibc 2.1). |
| 941 | // |
| 942 | // Note that glibc only compiles in the legacy compatibility code for some targets; it |
| 943 | // depends on what is defined in the `shlib-versions` file for the particular architecture |
| 944 | // and ABI. Those files are preprocessed by 2 separate tools during the glibc build to get |
| 945 | // the final `abi-versions.h`, so it would be quite brittle to try to condition our emission |
| 946 | // of the `_IO_stdin_used` reference in the exact same way. The only downside of emitting |
| 947 | // the reference unconditionally is that it ends up being unused for newer targets; it |
| 948 | // otherwise has no negative effect. |
| 949 | // |
| 950 | // glibc uses a weak reference because it has to work with programs compiled against pre-2.1 |
| 951 | // versions where the symbol didn't exist. We only care about modern glibc versions, so use |
| 952 | // a strong reference. |
| 953 | if (std.mem.eql(u8, lib.name, "c")) { |
| 954 | try stubs_asm.writer().print( |
| 955 | \\.globl _IO_stdin_used |
| 956 | \\{s} _IO_stdin_used |
| 957 | \\ |
| 958 | , .{wordDirective(target)}); |
| 959 | } |
| 960 | |
| 926 | 961 | const obj_inclusions_len = mem.readInt(u16, metadata.inclusions[inc_i..][0..2], .little); |
| 927 | 962 | inc_i += 2; |
| 928 | 963 | |