Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

zig cc: frexp() segfaults on Windows with bad call address #9845

Closed
jcmoyer opened this issue Sep 26, 2021 · 14 comments · Fixed by #9852
Closed

zig cc: frexp() segfaults on Windows with bad call address #9845

jcmoyer opened this issue Sep 26, 2021 · 14 comments · Fixed by #9852
Labels
bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. os-windows standard library This issue involves writing Zig code for the standard library.
Milestone

Comments

@jcmoyer
Copy link
Contributor

jcmoyer commented Sep 26, 2021

Platform: Windows 10 20H2 x64.

Zig 1f2f9f0 built with MSVC 16.10.2.30804 using llvm+clang+lld-12.0.1-rc1-x86_64-windows-msvc-release-mt from the wiki page.

Compiling with that same version of clang produces a working executable.

Code:

// test.c
#include <stdio.h>
#include <math.h>

int main(int argc, char* argv[]) {
    int i;
    printf("frexp at %p\n", frexp);
    double x = frexp(100.0, &i);
    printf("%f = %f * 2^%d\n", x * pow(2, i), x, i);
    return 0;
}

Compile with zig cc -g test.c

This prints: frexp at 00007ff5b19ee9d0 and then segfaults. It doesn't matter if the build is -O0 or -O3.

lldb says:

(lldb) bt
* thread #1, stop reason = Exception 0xc0000005 encountered at address 0x7ff5b19ee9d0: User-mode data execution prevention (DEP) violation at location 0x7ff5b19ee9d0
  * frame #0: 0x00007ff5b19ee9d0
    frame #1: 0x00007ff6089a104b a.exe`main(argc=<unavailable>, argv=<unavailable>) at test.c:7
    frame #2: 0x00007ff6089a1528 a.exe`WinMainCRTStartup + 696
    frame #3: 0x00007ff6089a1576 a.exe`mainCRTStartup + 22
    frame #4: 0x00007ffcb15e7034 kernel32.dll`BaseThreadInitThunk + 20
    frame #5: 0x00007ffcb2142651 ntdll.dll`RtlUserThreadStart + 33

(lldb) up
frame #1: 0x00007ff6089a104b a.exe`main(argc=<unavailable>, argv=<unavailable>) at test.c:7
   4    int main(int argc, char* argv[]) {
   5      int i;
   6      printf("frexp at %p\n", frexp);
-> 7      double x = frexp(100.0, &i);
   8      printf("%f = %f * 2^%d\n", x * pow(2, i), x, i);
   9      return 0;
   10   }

(lldb) disas
a.exe`main:
    0x7ff6089a1000 <+0>:   pushq  %rbp
    0x7ff6089a1001 <+1>:   pushq  %rsi
    0x7ff6089a1002 <+2>:   pushq  %rdi
    0x7ff6089a1003 <+3>:   subq   $0x40, %rsp
    0x7ff6089a1007 <+7>:   leaq   0x40(%rsp), %rbp
    0x7ff6089a100c <+12>:  vmovaps %xmm6, -0x10(%rbp)
    0x7ff6089a1011 <+17>:  movq   0xe018(%rip), %rdi        ; .refptr.__stack_chk_guard
    0x7ff6089a1018 <+24>:  callq  0x7ff6089a1660            ; __main
    0x7ff6089a101d <+29>:  movq   (%rdi), %rax
    0x7ff6089a1020 <+32>:  xorq   %rbp, %rax
    0x7ff6089a1023 <+35>:  movq   %rax, -0x18(%rbp)
    0x7ff6089a1027 <+39>:  leaq   0xdfe2(%rip), %rcx
    0x7ff6089a102e <+46>:  leaq   -0x56fb2665(%rip), %rdx
    0x7ff6089a1035 <+53>:  callq  0x7ff6089a10b0            ; printf at stdio.h:369
    0x7ff6089a103a <+58>:  vmovsd 0xdfbe(%rip), %xmm0       ; xmm0 = mem[0],zero
    0x7ff6089a1042 <+66>:  leaq   -0x1c(%rbp), %rdx
    0x7ff6089a1046 <+70>:  callq  0x7ff5b19ee9d0
->  0x7ff6089a104b <+75>:  vmovapd %xmm0, %xmm6
    0x7ff6089a104f <+79>:  movl   -0x1c(%rbp), %esi
    0x7ff6089a1052 <+82>:  vmovsd 0xdfae(%rip), %xmm0       ; xmm0 = mem[0],zero
    0x7ff6089a105a <+90>:  movl   %esi, %edx
    0x7ff6089a105c <+92>:  callq  0x7ff6089a1f20            ; ldexp
    0x7ff6089a1061 <+97>:  vmulsd %xmm0, %xmm6, %xmm1
    0x7ff6089a1065 <+101>: leaq   0xdfb1(%rip), %rcx
    0x7ff6089a106c <+108>: vmovq  %xmm1, %rdx
    0x7ff6089a1071 <+113>: vmovapd %xmm6, %xmm2
    0x7ff6089a1075 <+117>: vmovq  %xmm6, %r8
    0x7ff6089a107a <+122>: movl   %esi, %r9d
    0x7ff6089a107d <+125>: callq  0x7ff6089a10b0            ; printf at stdio.h:369
    0x7ff6089a1082 <+130>: movq   -0x18(%rbp), %rax
    0x7ff6089a1086 <+134>: xorq   %rbp, %rax
    0x7ff6089a1089 <+137>: movq   (%rdi), %rcx
    0x7ff6089a108c <+140>: cmpq   %rax, %rcx
    0x7ff6089a108f <+143>: jne    0x7ff6089a10a0            ; <+160> at test.c:9
    0x7ff6089a1091 <+145>: xorl   %eax, %eax
    0x7ff6089a1093 <+147>: vmovaps -0x10(%rbp), %xmm6
    0x7ff6089a1098 <+152>: addq   $0x40, %rsp
    0x7ff6089a109c <+156>: popq   %rdi
    0x7ff6089a109d <+157>: popq   %rsi
    0x7ff6089a109e <+158>: popq   %rbp
    0x7ff6089a109f <+159>: retq
    0x7ff6089a10a0 <+160>: callq  0x7ff6089a2080            ; __stack_chk_fail
    0x7ff6089a10a5 <+165>: int3

The call right before the arrow is suspect, callq 0x7ff5b19ee9d0

This address is not executable (and it is not mapped), note that all code exists above 0x7ff6089a0000:

(lldb) image dump sections
Dumping sections for 5 modules.
Sections for 'D:\...\a.exe' (x86_64):
  SectID     Type             Load Address                             Perm File Off.  File Size  Flags      Section Name
  ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
  0xffffffffffffffff regular  [0x00007ff6089a0000-0x00007ff6089a0400)  r--  0x00000000 0x00000400 0x00000000 a.exe.PECOFF header
  0x00000001 code             [0x00007ff6089a1000-0x00007ff6089aec66)  r-x  0x00000400 0x0000de00 0x60000020 a.exe..text
  0x00000002 data             [0x00007ff6089af000-0x00007ff6089b046c)  r--  0x0000e200 0x00001600 0x40000040 a.exe..rdata
  0x00000003 data             [0x00007ff6089b1000-0x00007ff6089b107f)  r--  0x0000f800 0x00000200 0x40000040 a.exe..buildid
  0x00000004 data             [0x00007ff6089b2000-0x00007ff6089b3b40)  rw-  0x0000fa00 0x00000200 0xc0000040 a.exe..data  
  0x00000005 data             [0x00007ff6089b4000-0x00007ff6089b463c)  r--  0x0000fc00 0x00000800 0x40000040 a.exe..pdata
  0x00000006 data             [0x00007ff6089b5000-0x00007ff6089b5010)  rw-  0x00010400 0x00000200 0xc0000040 a.exe..tls
  0x00000007 regular          [0x00007ff6089b6000-0x00007ff6089b6080)  r--  0x00010600 0x00000200 0x42000040 a.exe..reloc
Sections for 'C:\Windows\System32\ntdll.dll' (x86_64):
  SectID     Type             Load Address                             Perm File Off.  File Size  Flags      Section Name
  ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
  0xffffffffffffffff regular  [0x00007ffcb20f0000-0x00007ffcb20f0400)  r--  0x00000000 0x00000400 0x00000000 ntdll.dll.PECOFF header
  0x00000001 code             [0x00007ffcb20f1000-0x00007ffcb2209f1e)  r-x  0x00000400 0x00119000 0x60000020 ntdll.dll..text
  0x00000002 code             [0x00007ffcb220a000-0x00007ffcb220a592)  r-x  0x00119400 0x00000600 0x60000020 ntdll.dll.PAGE
  0x00000003 code             [0x00007ffcb220b000-0x00007ffcb220b1f9)  r-x  0x00119a00 0x00000200 0x60000020 ntdll.dll.RT
  0x00000004 data             [0x00007ffcb220c000-0x00007ffcb2253fe1)  r--  0x00119c00 0x00048000 0x40000040 ntdll.dll..rdata
  0x00000005 data             [0x00007ffcb2254000-0x00007ffcb225f518)  rw-  0x00161c00 0x00004000 0xc0000040 ntdll.dll..data
  0x00000006 data             [0x00007ffcb2260000-0x00007ffcb226e4fc)  r--  0x00165c00 0x0000e600 0x40000040 ntdll.dll..pdata
  0x00000007 data             [0x00007ffcb226f000-0x00007ffcb2272520)  rw-  0x00174200 0x00003600 0xc0000040 ntdll.dll..mrdata
  0x00000008 data             [0x00007ffcb2273000-0x00007ffcb2273008)  r--  0x00177800 0x00000200 0x40000040 ntdll.dll..00cfg
  0x00000009 data             [0x00007ffcb2274000-0x00007ffcb22e3dc8)  r--  0x00177a00 0x0006fe00 0x40000040 ntdll.dll..rsrc
  0x0000000a regular          [0x00007ffcb22e4000-0x00007ffcb22e4548)  r--  0x001e7800 0x00000600 0x42000040 ntdll.dll..reloc
Sections for 'C:\Windows\System32\kernel32.dll' (x86_64):
  SectID     Type             Load Address                             Perm File Off.  File Size  Flags      Section Name
  ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
  0xffffffffffffffff regular  [0x00007ffcb15d0000-0x00007ffcb15d0400)  r--  0x00000000 0x00000400 0x00000000 kernel32.dll.PECOFF header
  0x00000001 code             [0x00007ffcb15d1000-0x00007ffcb164e23b)  r-x  0x00000400 0x0007d400 0x60000020 kernel32.dll..text
  0x00000002 data             [0x00007ffcb164f000-0x00007ffcb1681e86)  r--  0x0007d800 0x00033000 0x40000040 kernel32.dll..rdata
  0x00000003 data             [0x00007ffcb1682000-0x00007ffcb168321c)  rw-  0x000b0800 0x00000600 0xc0000040 kernel32.dll..data
  0x00000004 data             [0x00007ffcb1684000-0x00007ffcb1689550)  r--  0x000b0e00 0x00005600 0x40000040 kernel32.dll..pdata
  0x00000005 data             [0x00007ffcb168a000-0x00007ffcb168a068)  rw-  0x000b6400 0x00000200 0xc0000040 kernel32.dll..didat
  0x00000006 data             [0x00007ffcb168b000-0x00007ffcb168b520)  r--  0x000b6600 0x00000600 0x40000040 kernel32.dll..rsrc
  0x00000007 regular          [0x00007ffcb168c000-0x00007ffcb168c300)  r--  0x000b6c00 0x00000400 0x42000040 kernel32.dll..reloc
Sections for 'C:\Windows\System32\KernelBase.dll' (x86_64):
  SectID     Type             Load Address                             Perm File Off.  File Size  Flags      Section Name
  ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
  0xffffffffffffffff regular  [0x00007ffcafd50000-0x00007ffcafd50400)  r--  0x00000000 0x00000400 0x00000000 KernelBase.dll.PECOFF header
  0x00000001 code             [0x00007ffcafd51000-0x00007ffcafe618dd)  r-x  0x00000400 0x00110a00 0x60000020 KernelBase.dll..text
  0x00000002 data             [0x00007ffcafe62000-0x00007ffcaffd935a)  r--  0x00110e00 0x00177400 0x40000040 KernelBase.dll..rdata
  0x00000003 data             [0x00007ffcaffda000-0x00007ffcaffde440)  rw-  0x00288200 0x00001400 0xc0000040 KernelBase.dll..data
  0x00000004 data             [0x00007ffcaffdf000-0x00007ffcaffed7e4)  r--  0x00289600 0x0000e800 0x40000040 KernelBase.dll..pdata
  0x00000005 data             [0x00007ffcaffee000-0x00007ffcaffee6c8)  rw-  0x00297e00 0x00000800 0xc0000040 KernelBase.dll..didat
  0x00000006 data             [0x00007ffcaffef000-0x00007ffcaffef548)  r--  0x00298600 0x00000600 0x40000040 KernelBase.dll..rsrc
  0x00000007 regular          [0x00007ffcafff0000-0x00007ffcb00179f0)  r--  0x00298c00 0x00027a00 0x42000040 KernelBase.dll..reloc
Sections for 'C:\Windows\System32\msvcrt.dll' (x86_64):
  SectID     Type             Load Address                             Perm File Off.  File Size  Flags      Section Name
  ---------- ---------------- ---------------------------------------  ---- ---------- ---------- ---------- ----------------------------
  0xffffffffffffffff regular  [0x00007ffcb1980000-0x00007ffcb1980400)  r--  0x00000000 0x00000400 0x00000000 msvcrt.dll.PECOFF header
  0x00000001 code             [0x00007ffcb1981000-0x00007ffcb19f56d1)  r-x  0x00000400 0x00074800 0x60000020 msvcrt.dll..text
  0x00000002 data             [0x00007ffcb19f6000-0x00007ffcb1a0ecc0)  r--  0x00074c00 0x00018e00 0x40000040 msvcrt.dll..rdata
  0x00000003 data             [0x00007ffcb1a0f000-0x00007ffcb1a16c00)  rw-  0x0008da00 0x00005600 0xc0000040 msvcrt.dll..data
  0x00000004 data             [0x00007ffcb1a17000-0x00007ffcb1a1b65c)  r--  0x00093000 0x00004800 0x40000040 msvcrt.dll..pdata
  0x00000005 data             [0x00007ffcb1a1c000-0x00007ffcb1a1c3f0)  r--  0x00097800 0x00000400 0x40000040 msvcrt.dll..rsrc
  0x00000006 regular          [0x00007ffcb1a1d000-0x00007ffcb1a1d4a8)  r--  0x00097c00 0x00000600 0x42000040 msvcrt.dll..reloc

I'm not really sure how to go about debugging this further, any assistance would be greatly appreciated.

@drew-gpf
Copy link
Contributor

drew-gpf commented Sep 27, 2021

This looks like either a linker bug or a Windows loader bug when using MinGW headers.
Compiling the C app with the default command line (which uses MinGW) produces a normal-looking import from msvcrt:
image
image
While compiling with zig cc --target=x86_64-windows-msvc -O3 (which clang does by default) will inline frexp:
image
image
And produce an output:

frexp at 00007FF708572918
100.000000 = 0.781250 * 2^7

Which should be an acceptable solution assuming you aren't cross compiling. This doesn't seem to be a problem with MSVCRT itself as manually calling frexp with GetProcAddress works fine:

// test.c
#include <stdio.h>
#include <math.h>
#include <windows.h>

int main(int argc, char* argv[]) {
    int i;
    printf("frexp at %p\n", frexp);
    const FARPROC frexp_manual = GetProcAddress(GetModuleHandle("MSVCRT"), "frexp");
    printf("other frexp at %p\n", frexp_manual);
    double x = ((double(*)(double, int*))(frexp_manual))(100.0, &i);
    printf("%f = %f * 2^%d\n", x * pow(2, i), x, i);
    return 0;
}

Produces

frexp at 00007ff62a28e9d0
other frexp at 00007ffb2a28e9d0
100.000000 = 0.781250 * 2^7

Note how (other frexp - frexp) = 0x5_0000_0000; the imported frexp is exactly 20GiB off of where it should be, for some reason. I'm not sure what to make of that.
Just for fun, the Zig equivalent executable does the same thing:

//! zigtest.zig
const std = @import("std");
extern fn frexp(_X: f64, _Y: *c_int) f64;
extern fn pow(_X: f64, _Y: f64) f64;

pub fn main() !void {
    var i: c_int = undefined;

    const writer = std.io.getStdOut().writer();
    try writer.print("frexp at {}\n", .{ frexp });
    const x = frexp(100.0, &i);
    try writer.print("{} = {} * 2^{}\n", .{ x * pow(2.0, @intToFloat(f64, i)), x, i });
}

With zig run zigtest.zig -OReleaseFast -lc:

frexp at fn(f64, *c_int) callconv(.C) f64@7ff62a28e9d0
<crashes>

With zig run zigtest.zig -target x86_64-windows-msvc -OReleaseFast -lc:

frexp at fn(f64, *c_int) callconv(.C) f64@7ff7ab49da58
1.0e+02 = 7.8125e-01 * 2^7

@jcmoyer
Copy link
Contributor Author

jcmoyer commented Sep 28, 2021

Good finds. Compiling with x86_64-windows-msvc also solves the problem for me. I've been poking at this in a debugger for a while and found that the address is being rewritten by a function called _pei386_runtime_relocator (part of mingw) which does pseudo-relocation at startup.

dumpbin says:

OPTIONAL HEADER VALUES
    140000000 image base (0000000140000000 to 000000014001FFFF)

SECTION HEADER #1
   .text name
   16F56 virtual size
    1000 virtual address (0000000140001000 to 0000000140017F55)

On my machine, the executable loads at 00007FF7072C0000.

On load the call instruction is

00007FF7072C1067 | E8 BC7A0100              | call    <a.&frexp>                       | (call 7FF7072D8B28) RVA = 18B28

Adding one byte for the opcode gives an RVA for the address, 1068.

We can look at memory located at __RUNTIME_PSEUDO_RELOC_LIST__. The first 12 bytes is a header, following is an array of:

typedef struct {
  DWORD sym;
  DWORD target;
  DWORD flags;
} runtime_pseudo_reloc_item_v2;

In my case, sym = 00018B28 (RVA of frexp)
target = 00001068 (RVA of the call operand)
flags = 00000020

Then the relocator looks at the call operand, does some bitwise magic, and writes a new operand. The instruction becomes

00007FF7072C1067 | E8 64D972AA              | call    7FF6B19EE9D0

I suppose I'll try to raise this with the people over at mingw and see what they have to say.

@mstorsjo
Copy link

TL;DR

Zig's libmsvcrt.a is missing math/frexp.c, declared in https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-crt/Makefile.am#L183.

Background/explanation of dllimport technicalities:

When referencing a symbol foo in another DLL, the address of foo is fetched from the import address table entry __imp_foo. E.g.:

$ cat import.c 
void __declspec(dllimport) importedFunc(void);
void localFunc(void);
void call(void) {
    importedFunc();
    localFunc();
}
$ x86_64-w64-mingw32-gcc import.c -S -o -
call:
        callq   *__imp_importedFunc(%rip)
        callq   localFunc
        retq

When calling a function which wasn't declared dllimport in the source code (like localFunc in the example), the call goes to a local thunk which loads the real target address from *__imp_importedFunc and the jumps there; the import lib and/or the linker provides that thunk.

The same goes when accessing data:

$ cat import2.c 
extern int __declspec(dllimport) importedData;
int localData;
int get(void) {
    return localData + importedData;
}
$ x86_64-w64-mingw32-gcc import2.c -S -o -
get:
        movl    localData(%rip), %eax
        movq    __imp_importedData(%rip), %rcx
        addl    (%rcx), %eax
        retq

When accessing a variable, and the generated code didn't have the variable flagged dllimport, but turns out to need to be imported from another DLL, one can't just jump through a linker-provided thunk. Instead, the linker adds entries to the runtime pseudo relocation list, which the mingw runtime then runs through at startup, and rewrites the addresses.

If the addresses are located in the text section, this requires remapping the text sections as read-write-execute for a while, do the fixups, and then remap them as readonly-execute again. Also, if the code expected the target address to be within 4 GB from the source address (with 32 bit RIP-relative addressing), but the address turned out to actually be further away than that, in the 64 bit address space, the runtime pseudo relocation can't fix that.

For data variables that might need to be dllimported, the compiler (both GCC and Clang) actually generate something to ease this:

$ cat import3.c 
extern int maybeLocalData;
int get(void) {
    return maybeLocalData;
}
$ x86_64-w64-mingw32-gcc import3.c -S -o -
get:
        movq    .refptr.maybeLocalData(%rip), %rax
        movl    (%rax), %eax
        retq

        .section        .rdata$.refptr.maybeLocalData,"dr",discard,.refptr.maybeLocalData
.refptr.maybeLocalData:
        .quad   maybeLocalData

So in this case, the full 64 bit address to maybeLocalData is stored elsewhere, and the code fetches the address from there.

Back to the issue at hand

In the case of frexp in mingw-w64, the msvcrt.dll provided frexp was reimplemented in mingw-w64-crt a couple years ago (because the msvcrt.dll provided version does the wrong thing in a couple of corner cases): mingw-w64/mingw-w64@8331eb0

In that commit, a new statically linked frexp is provided in the msvcrt.dll import library (libmsvcrt-os.a and libmsvcrt.a if msvcrt-os, the one targeting msvcrt.dll, is the default choice), and the actual dllimport version of it is marked DATA (so that it doesn't provide the frexp symbol, only __imp_frexp).

If using UCRT instead of msvcrt.dll, then the regular frexp symbol is exported from there as normal, and no mingw-w64 specific version is provided, because the UCRT implementation is considered correct enough.

Now when Zig's libmsvcrt.a didn't contain the frexp symbol, but did contain __imp_frexp, the linker thought it was a data symbol that had to be auto-imported - but at runtime it turned out to be too far away (further than the 4 GB range allowed by the 32 bit offset in the instruction opcode). (In the same case, if compiled with GCC, the compiler actually inserted a .refptr.frexp just like for maybeLocalData above, but Clang doesn't do that for functions, only for data.)

@mstorsjo
Copy link

TL;DR 2: There's lots of very subtle interactions between the import libs/def files and statically linked helper functions (scattered across libmingwex.a, libmsvcrt.a, libucrt.a, libws2_32.a, etc), and the helpers are moved from one lib to another occasionally.

AFAIK the strategy from Zig so far has been to just include the things that empirically has been noted as needed, adding more files one by one, but at this point I think it might be worthwhile to do a full sweep trying to match what mingw-w64-crt's Makefile.am does, to avoid needing to spend time on debugging them one by one. (Most of them are probably easier to debug and analyze, but this one was a bit non-obvious.)

@jcmoyer
Copy link
Contributor Author

jcmoyer commented Sep 28, 2021

Thank you for taking the time to write up such a detailed explanation; it turns out the fix was much simpler than tracking down the problem.

@jcmoyer
Copy link
Contributor Author

jcmoyer commented Oct 6, 2021

Alright so after about a week of testing with mingw's frexp.c this issue has appeared again (haven't updated zig since then, I've just using the patch in the above PR). I suspect the fix never worked and there's some element of randomness to how the linker goes about resolving the function, or I'm misunderstanding how zig's msvcrt is built.

@mstorsjo
Copy link

mstorsjo commented Oct 6, 2021

Alright so after about a week of testing with mingw's frexp.c this issue has appeared again (haven't updated zig since then, I've just using the patch in the above PR). I suspect the fix never worked and there's some element of randomness to how the linker goes about resolving the function.

If the mingw-w64-crt implementation of frexp is included in the link, then there should be no randomness, but that one should be picked and preferred over __imp_frexp (which is what ends up included with autoimport fixups otherwise, when you have the issue).

For a build that fails, can you 1) doublecheck that there really is an object file that provides frexp in the build, and 2) get a log of the linker output with the flag -verbose added?

@jcmoyer
Copy link
Contributor Author

jcmoyer commented Oct 6, 2021

For #1, how can you verify an object file actually contains an implementation? Based on the linker output I'm guessing it should be finding frexp in mingwex.lib, but it's not. It only has:

    316D6 frexpf
    319AC frexpl

As far as I can tell, frexp.c is being compiled, according to dumpbin mingwex.lib /all:

Archive member name at 3150E: /8622           C:\Users\jcmoyer\AppData\Local\zig\o\783b9c3f88bc91e5f955834d61a86572\frexp.obj
Archive member name at 316D6: /8702           C:\Users\jcmoyer\AppData\Local\zig\o\6c17efbd06f3eaa0e54a50ceb47c991e\frexpf.obj
Archive member name at 319AC: /8783           C:\Users\jcmoyer\AppData\Local\zig\o\fa1860ab70a6676907f3d74703d71342\frexpl.obj

Linker output:

d:\Scratch\repro>zig lld-link -verbose -ERRORLIMIT:0 -NOLOGO -DEBUG -STACK:16777216 -MACHINE:X64 -OUT:C:\Users\jcmoyer\AppData\Local\zig\o\f5f7e721d09fcc0201f849234a79bb95\a.exe C:\Users\jcmoyer\AppData\Local\zig\o\e0d8a064d4071b783bd92b3369aabea5\test.obj -lldmingw -ALTERNATENAME:__image_base__=__ImageBase C:\Users\jcmoyer\AppData\Local\zig\o\ae2d81930c44b1789202018633c30699\crt2.obj C:\Users\jcmoyer\AppData\Local\zig\o\15ff7ee79775d14f22d29dd64e37acab\mingw32.lib C:\Users\jcmoyer\AppData\Local\zig\o\713efcdf50a9558145e8036a2f9d65c7\mingwex.lib C:\Users\jcmoyer\AppData\Local\zig\o\833ae0dda25e8172ae7411afc41bd6a9\msvcrt-os.lib C:\Users\jcmoyer\AppData\Local\zig\o\e5f24f6e382de304c1c19623a8b037b8\ssp.lib C:\Users\jcmoyer\AppData\Local\zig\o\71c1495384faf25e6adb2338e5f29254\compiler_rt.lib C:\Users\jcmoyer\AppData\Local\zig\o\6d63934477553e6448ced81821ac07f7\advapi32.lib C:\Users\jcmoyer\AppData\Local\zig\o\91f4f51e6660c4af67d1a88e42df1941\kernel32.lib C:\Users\jcmoyer\AppData\Local\zig\o\3b0d10d6c729f5c6bbcf83c08cfcff3f\msvcrt.lib C:\Users\jcmoyer\AppData\Local\zig\o\7f7b47faa560d9bfcf29ff97f304c281\ntdll.lib C:\Users\jcmoyer\AppData\Local\zig\o\07f06041dbfe43675fac95d943c0df37\shell32.lib C:\Users\jcmoyer\AppData\Local\zig\o\67576e6b736bc434554fbbf6264def63\user32.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\e0d8a064d4071b783bd92b3369aabea5\test.obj
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\ae2d81930c44b1789202018633c30699\crt2.obj
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\15ff7ee79775d14f22d29dd64e37acab\mingw32.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\713efcdf50a9558145e8036a2f9d65c7\mingwex.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\833ae0dda25e8172ae7411afc41bd6a9\msvcrt-os.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\e5f24f6e382de304c1c19623a8b037b8\ssp.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\71c1495384faf25e6adb2338e5f29254\compiler_rt.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\6d63934477553e6448ced81821ac07f7\advapi32.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\91f4f51e6660c4af67d1a88e42df1941\kernel32.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\3b0d10d6c729f5c6bbcf83c08cfcff3f\msvcrt.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\7f7b47faa560d9bfcf29ff97f304c281\ntdll.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\07f06041dbfe43675fac95d943c0df37\shell32.lib
lld-link: Reading C:\Users\jcmoyer\AppData\Local\zig\o\67576e6b736bc434554fbbf6264def63\user32.lib
lld-link: Reading mingw32.lib(gccmain.obj)
lld-link: Loaded mingw32.lib(gccmain.obj) for __main
lld-link: Reading mingw32.lib(natstart.obj)
lld-link: Loaded mingw32.lib(natstart.obj) for __native_startup_state
lld-link: Reading mingw32.lib(wildcard.obj)
lld-link: Loaded mingw32.lib(wildcard.obj) for _dowildcard
lld-link: Reading mingw32.lib(charmax.obj)
lld-link: Loaded mingw32.lib(charmax.obj) for mingw_initcharmax
lld-link: Reading mingw32.lib(dllargv.obj)
lld-link: Loaded mingw32.lib(dllargv.obj) for _setargv
lld-link: Reading mingw32.lib(_newmode.obj)
lld-link: Loaded mingw32.lib(_newmode.obj) for _newmode
lld-link: Reading mingw32.lib(tlssup.obj)
lld-link: Loaded mingw32.lib(tlssup.obj) for __dyn_tls_init_callback
lld-link: Reading mingw32.lib(xncommod.obj)
lld-link: Loaded mingw32.lib(xncommod.obj) for _commode
lld-link: Reading mingw32.lib(cinitexe.obj)
lld-link: Loaded mingw32.lib(cinitexe.obj) for __xi_a
lld-link: Reading mingw32.lib(merr.obj)
lld-link: Loaded mingw32.lib(merr.obj) for _matherr
lld-link: Reading mingw32.lib(usermatherr.obj)
lld-link: Loaded mingw32.lib(usermatherr.obj) for __mingw_setusermatherr
lld-link: Reading mingw32.lib(CRT_fp10.obj)
lld-link: Loaded mingw32.lib(CRT_fp10.obj) for _fpreset
lld-link: Reading mingw32.lib(mingw_helpers.obj)
lld-link: Loaded mingw32.lib(mingw_helpers.obj) for mingw_app_type
lld-link: Reading mingw32.lib(pseudo-reloc.obj)
lld-link: Loaded mingw32.lib(pseudo-reloc.obj) for _pei386_runtime_relocator
lld-link: Reading mingw32.lib(xtxtmode.obj)
lld-link: Loaded mingw32.lib(xtxtmode.obj) for _fmode
lld-link: Reading mingw32.lib(crt_handler.obj)
lld-link: Loaded mingw32.lib(crt_handler.obj) for _gnu_exception_handler
lld-link: Reading mingwex.lib(mingw_matherr.obj)
lld-link: Loaded mingwex.lib(mingw_matherr.obj) for _MINGW_INSTALL_DEBUG_MATHERR
lld-link: Reading mingwex.lib(mingw_vfprintf.obj)
lld-link: Loaded mingwex.lib(mingw_vfprintf.obj) for __mingw_vfprintf
lld-link: Reading mingwex.lib(ldexp.obj)
lld-link: Loaded mingwex.lib(ldexp.obj) for ldexp
lld-link: Reading msvcrt-os.lib(acrt_iob_func.obj)
lld-link: Loaded msvcrt-os.lib(acrt_iob_func.obj) for __declspec(dllimport) __acrt_iob_func
lld-link: Reading msvcrt-os.lib(invalid_parameter_handler.obj)
lld-link: Loaded msvcrt-os.lib(invalid_parameter_handler.obj) for _set_invalid_parameter_handler
lld-link: Reading msvcrt-os.lib(__p__acmdln.obj)
lld-link: Loaded msvcrt-os.lib(__p__acmdln.obj) for __p__acmdln
lld-link: Reading msvcrt-os.lib(__p__commode.obj)
lld-link: Loaded msvcrt-os.lib(__p__commode.obj) for __p__commode
lld-link: Reading msvcrt-os.lib(__p__fmode.obj)
lld-link: Loaded msvcrt-os.lib(__p__fmode.obj) for __p__fmode
lld-link: Reading ssp.lib(ssp.obj)
lld-link: Loaded ssp.lib(ssp.obj) for __stack_chk_fail
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading mingw32.lib(tlsthrd.obj)
lld-link: Loaded mingw32.lib(tlsthrd.obj) for __mingw_TLScallback
lld-link: Reading mingw32.lib(tlsmcrt.obj)
lld-link: Loaded mingw32.lib(tlsmcrt.obj) for _CRT_MT
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading mingw32.lib(pesect.obj)
lld-link: Loaded mingw32.lib(pesect.obj) for __mingw_GetSectionCount
lld-link: Reading compiler_rt.lib(compiler_rt.obj)
lld-link: Loaded compiler_rt.lib(compiler_rt.obj) for ___chkstk_ms
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading mingw32.lib(pseudo-reloc-list.obj)
lld-link: Loaded mingw32.lib(pseudo-reloc-list.obj) for __RUNTIME_PSEUDO_RELOC_LIST_END__
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt-os.lib(mingw_lock.obj)
lld-link: Loaded msvcrt-os.lib(mingw_lock.obj) for _lock_file
lld-link: Reading mingwex.lib(mingw_pformat.obj)
lld-link: Loaded mingwex.lib(mingw_pformat.obj) for __mingw_pformat
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading msvcrt.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading mingwex.lib(mbrtowc.obj)
lld-link: Loaded mingwex.lib(mbrtowc.obj) for mbrtowc
lld-link: Reading msvcrt.dll
lld-link: Reading mingwex.lib(strnlen.obj)
lld-link: Loaded mingwex.lib(strnlen.obj) for strnlen
lld-link: Reading mingwex.lib(wcsnlen.obj)
lld-link: Loaded mingwex.lib(wcsnlen.obj) for wcsnlen
lld-link: Reading msvcrt.dll
lld-link: Reading mingwex.lib(gdtoa.obj)
lld-link: Loaded mingwex.lib(gdtoa.obj) for __gdtoa
lld-link: Reading mingwex.lib(dmisc.obj)
lld-link: Loaded mingwex.lib(dmisc.obj) for __freedtoa
lld-link: Reading mingwex.lib(wcrtomb.obj)
lld-link: Loaded mingwex.lib(wcrtomb.obj) for wcrtomb
lld-link: Reading msvcrt.dll
lld-link: Reading msvcrt.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading KERNEL32.dll
lld-link: Reading mingwex.lib(misc.obj)
lld-link: Loaded mingwex.lib(misc.obj) for __Balloc_D2A
lld-link: Reading mingwex.lib(gmisc.obj)
lld-link: Loaded mingwex.lib(gmisc.obj) for __trailz_D2A
lld-link: Reading KERNEL32.dll
lld-link: Entry name inferred: mainCRTStartup
lld-link: Loading lazy __imp_frexp from C:\Users\jcmoyer\AppData\Local\zig\o\3b0d10d6c729f5c6bbcf83c08cfcff3f\msvcrt.lib for automatic import
lld-link: Reading msvcrt.dll
lld-link: Automatically importing frexp from msvcrt.dll
lld-link: Processing section .CRT$XCA -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\918863d841aec4f5dc19feecd96bce85\cinitexe.obj, SectionID: 6
lld-link: Processing section .CRT$XCAA -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\ae2d81930c44b1789202018633c30699\crt2.obj, SectionID: 6
lld-link: Processing section .CRT$XCZ -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\918863d841aec4f5dc19feecd96bce85\cinitexe.obj, SectionID: 7
lld-link: Processing section .CRT$XDA -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\a709ba95b536ee38226011cf5331def7\tlssup.obj, SectionID: 10
lld-link: Processing section .CRT$XDZ -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\a709ba95b536ee38226011cf5331def7\tlssup.obj, SectionID: 11
lld-link: Processing section .CRT$XIA -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\918863d841aec4f5dc19feecd96bce85\cinitexe.obj, SectionID: 4
lld-link: Processing section .CRT$XIAA -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\ae2d81930c44b1789202018633c30699\crt2.obj, SectionID: 5
lld-link: Processing section .CRT$XIC -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\c9cc0cd91acd00a98c0fdad3baa35db4\charmax.obj, SectionID: 4
lld-link: Processing section .CRT$XIZ -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\918863d841aec4f5dc19feecd96bce85\cinitexe.obj, SectionID: 5
lld-link: Processing section .CRT$XLA -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\a709ba95b536ee38226011cf5331def7\tlssup.obj, SectionID: 7
lld-link: Processing section .CRT$XLC -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\a709ba95b536ee38226011cf5331def7\tlssup.obj, SectionID: 12
lld-link: Processing section .CRT$XLD -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\a709ba95b536ee38226011cf5331def7\tlssup.obj, SectionID: 13
lld-link: Processing section .CRT$XLZ -> .CRT
lld-link:   C:\Users\jcmoyer\AppData\Local\zig\o\a709ba95b536ee38226011cf5331def7\tlssup.obj, SectionID: 8
lld-link: Writing 2 runtime pseudo relocations

@mstorsjo
Copy link

mstorsjo commented Oct 6, 2021

I'd suggest trying llvm-nm (or plain nm from binutils) on your mingwex.lib, to see what symbols it provides in each object file there. (I presume dumpbin can do something similar, but I don't know the options offhand.)

Also, do note that you're not supposed to have frexp.c built into libmingwex, it's supposed to be in libmsvcrt: https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-crt/Makefile.am#L183 (It's added to the list of object files added to libmsvcrt.a.)

This, because mingwex is shared across all CRT variants (msvcrt.dll and UCRT); with UCRT we don't want to provide the mingw-w64 version but just use the UCRT version, but with msvcrt.dll, we want to bundle the frexp implementation along with it.

@jcmoyer
Copy link
Contributor Author

jcmoyer commented Oct 6, 2021

Alright, thanks for the guidance. I will try rebuilding zig with frexp.c as part of msvcrt. Presumably there's a difference in flags that could cause this behavior to occur.

Here's the output of nm mingwex.lib fwiw:

C:/Users/jcmoyer/AppData/Local/zig/o/783b9c3f88bc91e5f955834d61a86572/frexp.obj:
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 n .llvm_addrsig
0000000000000000 t .text
0000000000000000 a @feat.00

C:/Users/jcmoyer/AppData/Local/zig/o/6c17efbd06f3eaa0e54a50ceb47c991e/frexpf.obj:
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 n .llvm_addrsig
0000000000000000 p .pdata
0000000000000000 t .text
0000000000000000 r .xdata
0000000000000000 a @feat.00
                 U frexp
0000000000000000 T frexpf

C:/Users/jcmoyer/AppData/Local/zig/o/fa1860ab70a6676907f3d74703d71342/frexpl.obj:
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 n .llvm_addrsig
0000000000000000 p .pdata
0000000000000000 t .text
0000000000000000 r .xdata
0000000000000000 a @feat.00
0000000000000000 T frexpl

@mstorsjo
Copy link

mstorsjo commented Oct 6, 2021

Alright, thanks for the guidance. I will try rebuilding zig with frexp.c as part of msvcrt. Presumably there's a difference in flags that could cause this behavior to occur.

Well it won't affect this particular bug, but it could have other effects elsewhere down the line (like unnecessarily linking in the extra helper function if you switch to UCRT).

C:/Users/jcmoyer/AppData/Local/zig/o/783b9c3f88bc91e5f955834d61a86572/frexp.obj:
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 n .llvm_addrsig
0000000000000000 t .text
0000000000000000 a @feat.00

Ok, so this shows that you've got an object file that doesn't export any public functions here, it should have e.g. 0000000000000000 T frexp. Can you look into how this object file is compiled, what source it ends up using, etc - why isn't it providing the right symbol? (The file only has got one big #if, and if it doesn't hit the branch that provides the function, there's an #error.)

@jcmoyer
Copy link
Contributor Author

jcmoyer commented Oct 6, 2021

After recompiling it works again. Now there is definitely an frexp implementation:

>nm msvcrt-os.lib
C:/Users/jcmoyer/AppData/Local/zig/o/a7a902a7bb40529e0244470fb2145cfe/frexp.obj:
0000000000000000 b .bss
0000000000000000 d .data
0000000000000000 n .llvm_addrsig
0000000000000000 t .text
0000000000000000 a @feat.00
0000000000000000 T frexp

>zig lld-link ...
lld-link: Reading msvcrt-os.lib(frexp.obj)
lld-link: Loaded msvcrt-os.lib(frexp.obj) for frexp

Unfortunately I can't see a way to print the exact compile commands zig uses when building libc for the first time. The process takes place entirely within the zig compiler. I'll ask around in case you're still interested; personally I do not understand how building frexp.c into mingwex.lib does not include the implementation.

Based on src/mingw.zig, the compile command has at least these flags on my machine:

zig clang -DHAVE_CONFIG_H -ID:\zig-install\lib\zig\libc\mingw -ID:\zig-install\lib\zig\libc\mingw\include -std=gnu99 -D_CRTBLD -D_WIN32_WINNT=0x0f00 -D__MSVCRT_VERSION__=0x700 -isystem D:\zig-install\lib\zig\libc\include\any-windows-any D:\zig-install\lib\zig\libc\mingw\math\frexp.c

zig clang also defines __x86_64__ so it definitely can't hit the #error.

That command produces an object file with an frexp implementation for me, so I don't know if there's some other reason it's failing.

@jcmoyer
Copy link
Contributor Author

jcmoyer commented Oct 6, 2021

@mstorsjo here's the compile command from the faulty build:

D:\zig-install\bin\zig.exe clang -target x86_64-unknown-windows-gnu -nostdinc -fno-spell-checking -isystem D:\zig-install\lib\zig\include -Xclang -target-cpu -Xclang sandybridge -Xclang -target-feature -Xclang -16bit-mode -Xclang -target-feature -Xclang -32bit-mode -Xclang -target-feature -Xclang -3dnow -Xclang -target-feature -Xclang -3dnowa -Xclang -target-feature -Xclang +64bit -Xclang -target-feature -Xclang -adx -Xclang -target-feature -Xclang +aes -Xclang -target-feature -Xclang -amx-bf16 -Xclang -target-feature -Xclang -amx-int8 -Xclang -target-feature -Xclang -amx-tile -Xclang -target-feature -Xclang +avx -Xclang -target-feature -Xclang -avx2 -Xclang -target-feature -Xclang -avx512bf16 -Xclang -target-feature -Xclang -avx512bitalg -Xclang -target-feature -Xclang -avx512bw -Xclang -target-feature -Xclang -avx512cd -Xclang -target-feature -Xclang -avx512dq -Xclang -target-feature -Xclang -avx512er -Xclang -target-feature -Xclang -avx512f -Xclang -target-feature -Xclang -avx512ifma -Xclang -target-feature -Xclang -avx512pf -Xclang -target-feature -Xclang -avx512vbmi -Xclang -target-feature -Xclang -avx512vbmi2 -Xclang -target-feature -Xclang -avx512vl -Xclang -target-feature -Xclang -avx512vnni -Xclang -target-feature -Xclang -avx512vp2intersect -Xclang -target-feature -Xclang -avx512vpopcntdq -Xclang -target-feature -Xclang -avxvnni -Xclang -target-feature -Xclang -bmi -Xclang -target-feature -Xclang -bmi2 -Xclang -target-feature -Xclang -branchfusion -Xclang -target-feature -Xclang -cldemote -Xclang -target-feature -Xclang -clflushopt -Xclang -target-feature -Xclang -clwb -Xclang -target-feature -Xclang -clzero -Xclang -target-feature -Xclang +cmov -Xclang -target-feature -Xclang +cx16 -Xclang -target-feature -Xclang +cx8 -Xclang -target-feature -Xclang -enqcmd -Xclang -target-feature -Xclang -ermsb -Xclang -target-feature -Xclang -f16c -Xclang -target-feature -Xclang -false-deps-lzcnt-tzcnt -Xclang -target-feature -Xclang +false-deps-popcnt -Xclang -target-feature -Xclang -fast-11bytenop -Xclang -target-feature -Xclang +fast-15bytenop -Xclang -target-feature -Xclang -fast-7bytenop -Xclang -target-feature -Xclang -fast-bextr -Xclang -target-feature -Xclang -fast-gather -Xclang -target-feature -Xclang -fast-hops -Xclang -target-feature -Xclang -fast-lzcnt -Xclang -target-feature -Xclang +fast-scalar-fsqrt -Xclang -target-feature -Xclang -fast-scalar-shift-masks -Xclang -target-feature -Xclang +fast-shld-rotate -Xclang -target-feature -Xclang -fast-variable-shuffle -Xclang -target-feature -Xclang -fast-vector-fsqrt -Xclang -target-feature -Xclang -fast-vector-shift-masks -Xclang -target-feature -Xclang -fma -Xclang -target-feature -Xclang -fma4 -Xclang -target-feature -Xclang -fsgsbase -Xclang -target-feature -Xclang -fsrm -Xclang -target-feature -Xclang +fxsr -Xclang -target-feature -Xclang -gfni -Xclang -target-feature -Xclang -hreset -Xclang -target-feature -Xclang -idivl-to-divb -Xclang -target-feature -Xclang +idivq-to-divl -Xclang -target-feature -Xclang -invpcid -Xclang -target-feature -Xclang -kl -Xclang -target-feature -Xclang -lea-sp -Xclang -target-feature -Xclang -lea-uses-ag -Xclang -target-feature -Xclang -lvi-cfi -Xclang -target-feature -Xclang -lvi-load-hardening -Xclang -target-feature -Xclang -lwp -Xclang -target-feature -Xclang -lzcnt -Xclang -target-feature -Xclang +macrofusion -Xclang -target-feature -Xclang +mmx -Xclang -target-feature -Xclang -movbe -Xclang -target-feature -Xclang -movdir64b -Xclang -target-feature -Xclang -movdiri -Xclang -target-feature -Xclang -mwaitx -Xclang -target-feature -Xclang +nopl -Xclang -target-feature -Xclang -pad-short-functions -Xclang -target-feature -Xclang +pclmul -Xclang -target-feature -Xclang -pconfig -Xclang -target-feature -Xclang -pku -Xclang -target-feature -Xclang +popcnt -Xclang -target-feature -Xclang -prefer-128-bit -Xclang -target-feature -Xclang -prefer-256-bit -Xclang -target-feature -Xclang -prefer-mask-registers -Xclang -target-feature -Xclang -prefetchwt1 -Xclang -target-feature -Xclang -prfchw -Xclang -target-feature -Xclang -ptwrite -Xclang -target-feature -Xclang -rdpid -Xclang -target-feature -Xclang -rdrnd -Xclang -target-feature -Xclang -rdseed -Xclang -target-feature -Xclang -retpoline -Xclang -target-feature -Xclang -retpoline-external-thunk -Xclang -target-feature -Xclang -retpoline-indirect-branches -Xclang -target-feature -Xclang -retpoline-indirect-calls -Xclang -target-feature -Xclang -rtm -Xclang -target-feature -Xclang +sahf -Xclang -target-feature -Xclang -serialize -Xclang -target-feature -Xclang -seses -Xclang -target-feature -Xclang -sgx -Xclang -target-feature -Xclang -sha -Xclang -target-feature -Xclang -shstk -Xclang -target-feature -Xclang +slow-3ops-lea -Xclang -target-feature -Xclang -slow-incdec -Xclang -target-feature -Xclang -slow-lea -Xclang -target-feature -Xclang -slow-pmaddwd -Xclang -target-feature -Xclang -slow-pmulld -Xclang -target-feature -Xclang -slow-shld -Xclang -target-feature -Xclang -slow-two-mem-ops -Xclang -target-feature -Xclang -slow-unaligned-mem-16 -Xclang -target-feature -Xclang +slow-unaligned-mem-32 -Xclang -target-feature -Xclang -soft-float -Xclang -target-feature -Xclang +sse -Xclang -target-feature -Xclang +sse2 -Xclang -target-feature -Xclang +sse3 -Xclang -target-feature -Xclang +sse4.1 -Xclang -target-feature -Xclang +sse4.2 -Xclang -target-feature -Xclang -sse4a -Xclang -target-feature -Xclang -sse-unaligned-mem -Xclang -target-feature -Xclang +ssse3 -Xclang -target-feature -Xclang -tbm -Xclang -target-feature -Xclang -tsxldtrk -Xclang -target-feature -Xclang -uintr -Xclang -target-feature -Xclang -use-aa -Xclang -target-feature -Xclang -use-glm-div-sqrt-costs -Xclang -target-feature -Xclang -vaes -Xclang -target-feature -Xclang -vpclmulqdq -Xclang -target-feature -Xclang +vzeroupper -Xclang -target-feature -Xclang -waitpkg -Xclang -target-feature -Xclang -wbnoinvd -Xclang -target-feature -Xclang -widekl -Xclang -target-feature -Xclang +x87 -Xclang -target-feature -Xclang -xop -Xclang -target-feature -Xclang +xsave -Xclang -target-feature -Xclang -xsavec -Xclang -target-feature -Xclang +xsaveopt -Xclang -target-feature -Xclang -xsaves -Wno-pragma-pack -fomit-frame-pointer -mred-zone -DNDEBUG -O2 -fno-stack-protector -funwind-tables -MD -MV -MF C:\Users\jcmoyer\AppData\Local\zig\tmp\b6dc294377c47bfe-frexp.obj.d -c -o C:\Users\jcmoyer\AppData\Local\zig\tmp\b6dc294377c47bfe-frexp.obj D:\zig-install\lib\zig\libc\mingw\math\frexp.c -DHAVE_CONFIG_H -I D:\zig-install\lib\zig\libc\mingw -I D:\zig-install\lib\zig\libc\mingw\include -std=gnu99 -D_CRTBLD -D_WIN32_WINNT=0x0f00 -D__MSVCRT_VERSION__=0x700 -isystem D:\zig-install\lib\zig\libc\include\any-windows-any

And the compile command from the working build for comparison:

D:\zig-install\bin\zig.exe clang -target x86_64-unknown-windows-gnu -nostdinc -fno-spell-checking -isystem D:\zig-install\lib\zig\include -Xclang -target-cpu -Xclang sandybridge -Xclang -target-feature -Xclang -16bit-mode -Xclang -target-feature -Xclang -32bit-mode -Xclang -target-feature -Xclang -3dnow -Xclang -target-feature -Xclang -3dnowa -Xclang -target-feature -Xclang +64bit -Xclang -target-feature -Xclang -adx -Xclang -target-feature -Xclang +aes -Xclang -target-feature -Xclang -amx-bf16 -Xclang -target-feature -Xclang -amx-int8 -Xclang -target-feature -Xclang -amx-tile -Xclang -target-feature -Xclang +avx -Xclang -target-feature -Xclang -avx2 -Xclang -target-feature -Xclang -avx512bf16 -Xclang -target-feature -Xclang -avx512bitalg -Xclang -target-feature -Xclang -avx512bw -Xclang -target-feature -Xclang -avx512cd -Xclang -target-feature -Xclang -avx512dq -Xclang -target-feature -Xclang -avx512er -Xclang -target-feature -Xclang -avx512f -Xclang -target-feature -Xclang -avx512ifma -Xclang -target-feature -Xclang -avx512pf -Xclang -target-feature -Xclang -avx512vbmi -Xclang -target-feature -Xclang -avx512vbmi2 -Xclang -target-feature -Xclang -avx512vl -Xclang -target-feature -Xclang -avx512vnni -Xclang -target-feature -Xclang -avx512vp2intersect -Xclang -target-feature -Xclang -avx512vpopcntdq -Xclang -target-feature -Xclang -avxvnni -Xclang -target-feature -Xclang -bmi -Xclang -target-feature -Xclang -bmi2 -Xclang -target-feature -Xclang -branchfusion -Xclang -target-feature -Xclang -cldemote -Xclang -target-feature -Xclang -clflushopt -Xclang -target-feature -Xclang -clwb -Xclang -target-feature -Xclang -clzero -Xclang -target-feature -Xclang +cmov -Xclang -target-feature -Xclang +cx16 -Xclang -target-feature -Xclang +cx8 -Xclang -target-feature -Xclang -enqcmd -Xclang -target-feature -Xclang -ermsb -Xclang -target-feature -Xclang -f16c -Xclang -target-feature -Xclang -false-deps-lzcnt-tzcnt -Xclang -target-feature -Xclang +false-deps-popcnt -Xclang -target-feature -Xclang -fast-11bytenop -Xclang -target-feature -Xclang +fast-15bytenop -Xclang -target-feature -Xclang -fast-7bytenop -Xclang -target-feature -Xclang -fast-bextr -Xclang -target-feature -Xclang -fast-gather -Xclang -target-feature -Xclang -fast-hops -Xclang -target-feature -Xclang -fast-lzcnt -Xclang -target-feature -Xclang +fast-scalar-fsqrt -Xclang -target-feature -Xclang -fast-scalar-shift-masks -Xclang -target-feature -Xclang +fast-shld-rotate -Xclang -target-feature -Xclang -fast-variable-shuffle -Xclang -target-feature -Xclang -fast-vector-fsqrt -Xclang -target-feature -Xclang -fast-vector-shift-masks -Xclang -target-feature -Xclang -fma -Xclang -target-feature -Xclang -fma4 -Xclang -target-feature -Xclang -fsgsbase -Xclang -target-feature -Xclang -fsrm -Xclang -target-feature -Xclang +fxsr -Xclang -target-feature -Xclang -gfni -Xclang -target-feature -Xclang -hreset -Xclang -target-feature -Xclang -idivl-to-divb -Xclang -target-feature -Xclang +idivq-to-divl -Xclang -target-feature -Xclang -invpcid -Xclang -target-feature -Xclang -kl -Xclang -target-feature -Xclang -lea-sp -Xclang -target-feature -Xclang -lea-uses-ag -Xclang -target-feature -Xclang -lvi-cfi -Xclang -target-feature -Xclang -lvi-load-hardening -Xclang -target-feature -Xclang -lwp -Xclang -target-feature -Xclang -lzcnt -Xclang -target-feature -Xclang +macrofusion -Xclang -target-feature -Xclang +mmx -Xclang -target-feature -Xclang -movbe -Xclang -target-feature -Xclang -movdir64b -Xclang -target-feature -Xclang -movdiri -Xclang -target-feature -Xclang -mwaitx -Xclang -target-feature -Xclang +nopl -Xclang -target-feature -Xclang -pad-short-functions -Xclang -target-feature -Xclang +pclmul -Xclang -target-feature -Xclang -pconfig -Xclang -target-feature -Xclang -pku -Xclang -target-feature -Xclang +popcnt -Xclang -target-feature -Xclang -prefer-128-bit -Xclang -target-feature -Xclang -prefer-256-bit -Xclang -target-feature -Xclang -prefer-mask-registers -Xclang -target-feature -Xclang -prefetchwt1 -Xclang -target-feature -Xclang -prfchw -Xclang -target-feature -Xclang -ptwrite -Xclang -target-feature -Xclang -rdpid -Xclang -target-feature -Xclang -rdrnd -Xclang -target-feature -Xclang -rdseed -Xclang -target-feature -Xclang -retpoline -Xclang -target-feature -Xclang -retpoline-external-thunk -Xclang -target-feature -Xclang -retpoline-indirect-branches -Xclang -target-feature -Xclang -retpoline-indirect-calls -Xclang -target-feature -Xclang -rtm -Xclang -target-feature -Xclang +sahf -Xclang -target-feature -Xclang -serialize -Xclang -target-feature -Xclang -seses -Xclang -target-feature -Xclang -sgx -Xclang -target-feature -Xclang -sha -Xclang -target-feature -Xclang -shstk -Xclang -target-feature -Xclang +slow-3ops-lea -Xclang -target-feature -Xclang -slow-incdec -Xclang -target-feature -Xclang -slow-lea -Xclang -target-feature -Xclang -slow-pmaddwd -Xclang -target-feature -Xclang -slow-pmulld -Xclang -target-feature -Xclang -slow-shld -Xclang -target-feature -Xclang -slow-two-mem-ops -Xclang -target-feature -Xclang -slow-unaligned-mem-16 -Xclang -target-feature -Xclang +slow-unaligned-mem-32 -Xclang -target-feature -Xclang -soft-float -Xclang -target-feature -Xclang +sse -Xclang -target-feature -Xclang +sse2 -Xclang -target-feature -Xclang +sse3 -Xclang -target-feature -Xclang +sse4.1 -Xclang -target-feature -Xclang +sse4.2 -Xclang -target-feature -Xclang -sse4a -Xclang -target-feature -Xclang -sse-unaligned-mem -Xclang -target-feature -Xclang +ssse3 -Xclang -target-feature -Xclang -tbm -Xclang -target-feature -Xclang -tsxldtrk -Xclang -target-feature -Xclang -uintr -Xclang -target-feature -Xclang -use-aa -Xclang -target-feature -Xclang -use-glm-div-sqrt-costs -Xclang -target-feature -Xclang -vaes -Xclang -target-feature -Xclang -vpclmulqdq -Xclang -target-feature -Xclang +vzeroupper -Xclang -target-feature -Xclang -waitpkg -Xclang -target-feature -Xclang -wbnoinvd -Xclang -target-feature -Xclang -widekl -Xclang -target-feature -Xclang +x87 -Xclang -target-feature -Xclang -xop -Xclang -target-feature -Xclang +xsave -Xclang -target-feature -Xclang -xsavec -Xclang -target-feature -Xclang +xsaveopt -Xclang -target-feature -Xclang -xsaves -Wno-pragma-pack -fomit-frame-pointer -mred-zone -DNDEBUG -O2 -fno-stack-protector -funwind-tables -MD -MV -MF C:\Users\jcmoyer\AppData\Local\zig\tmp\6fd998b1102e7742-frexp.obj.d -c -o C:\Users\jcmoyer\AppData\Local\zig\tmp\6fd998b1102e7742-frexp.obj D:\zig-install\lib\zig\libc\mingw\math\frexp.c -DHAVE_CONFIG_H -D__LIBMSVCRT__ -I D:\zig-install\lib\zig\libc\mingw\include -std=gnu99 -D_CRTBLD -D_WIN32_WINNT=0x0f00 -D__MSVCRT_VERSION__=0x700 -isystem D:\zig-install\lib\zig\libc\include\any-windows-any

@andrewrk andrewrk added this to the 0.9.0 milestone Oct 7, 2021
@andrewrk andrewrk added bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. os-windows standard library This issue involves writing Zig code for the standard library. labels Oct 7, 2021
@mstorsjo
Copy link

mstorsjo commented Oct 7, 2021

@mstorsjo here's the compile command from the faulty build:

[snip]

And the compile command from the working build for comparison:

[snip]

The only difference between the two, modulo other random IDs, is that one of them has -D__LIBMSVCRT__ included. But that shouldn't seem to make any difference for how that's compiled. (I tried those commands, removing the local path specific bits and rebuilding it from the mingw-w64-crt source, and I got a proper frexp function both with and without -D__LIBMSVCRT__. So there's not really anything I can add here to explain why you end up with an object file with that function missing.

jon-y pushed a commit to mingw-w64/mingw-w64 that referenced this issue Oct 8, 2021
Normally, when correctly configured, the pseudo relocations should
be in fields that are large enough to hold the full target
offset/address. But if the relocations nevertheless end up truncated,
error out clearly instead of running into a hard to diagnose crash
at runtime.

The pseudo relocations can be applied both on absolute pointers and
relative offsets, so when writing a N bit number, we don't know if
the limits for it are unsigned or signed. Thus carefully allow
values from -(2^(N-1)) to (2^N)-1, covering the full range for both
signed and unsigned N bit numbers. This won't catch all cases where
offsets are out of bounds, but should catch the vast majority, allowing
a clearer error message in those situations.

By default, GCC builds for x86_64 with the medium code model, which
adds .refptr stubs when referencing addresses that might end up
autoimported (i.e. when referencing addresses that can be out of range
for a 32 bit offset). Some users, who don't expect to be autoimporting
any data symbols, might be building with -mcmodel=small [1], which
avoids this extra indirection - but which then silently breaks things
if actually ending up autoimporting data symbols from another DLL.

This can also happen if calling a function which is marked "DATA" in
the def files as it's not meant to be called/used normally (because we
provide a replacement in libmingwex or lib*crt* that we think should
be used instead). If the function that is meant to be called is missing
(this can happen in misconfigured builds where the libraries are lacking
symbols that we expect to provide, see [2]), the linker can end up doing
an autoimport of the function into a 32 bit RIP-relative offset.
(This only happens with Clang; GCC creates a .refptr stub for the
function in these cases, while Clang expects such stubs not to be needed
for functions, only for data.)

[1] https://code.videolan.org/videolan/dav1d/-/commit/8f7af99687533d15a9b5d16abc7b9d7b0cd4dcd0
[2] ziglang/zig#9845

Signed-off-by: Martin Storsjö <martin@martin.st>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Observed behavior contradicts documented or intended behavior contributor friendly This issue is limited in scope and/or knowledge of Zig internals. os-windows standard library This issue involves writing Zig code for the standard library.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants