Ensure the entrypoint is taken into account when computing the export table - #146
Ensure the entrypoint is taken into account when computing the export table#146dra27 wants to merge 4 commits into
Conversation
d08e8a0 to
63a7dbd
Compare
The defined_in function is used when determining which objects from the command line will actually be linked. However, this doesn't include the default libraries, which creates an issue for modules which are linked as a result of main. defined_in is augmented to include the mapping of symbols found in the default libraries, but some additional care is required to ensure that this doesn't cause imports from those to leak into the export table of the executable.
If -municode is passed to mingw-w64's gcc, then crt2u.o (which causes wmain to be selected) should be linked rather than crt2.o. In passing, the code now sniffs for -nostartfiles, which causes neither crt2.o nor crt2u.o to be considered.
The export table is determined by looping over the objects included on the command line. If the main symbol is included in a library (e.g. libcamlrun or libasmrun) then there may not be an object on the commandline which causes it, and any transitive dependencies, to be linked. The entrypoint symbol for the Cygwin/mingw-w64/MSVC toolchains is now resolved, and may cause additional objects to be linked.
nojb
left a comment
There was a problem hiding this comment.
I only glanced at the code, but LGTM
| Some "main" | ||
| | `MINGW | `MINGW64 -> begin | ||
| let entry_point s = | ||
| String.length s > 7 && String.sub s 0 7 = "-Wl,-e," |
There was a problem hiding this comment.
Isn't -Wl,-e rewritten into -link arguments (cf
Lines 281 to 285 in ab8161f
There was a problem hiding this comment.
Urgh - good catch, and unfortunately it's because this part is completely broken. The problem here is that when we link MSVC we actually call the linker, but when we link mingw-w64, we call the C compiler! I added this bit here for completeness - for MSVC, we of course select Unicode with -link /entry:wmainCRTStartup and that works because flexlink passes the /entry: directly to /link. For mingw-w64, we of course do -link -municode and that survives being passed to the C compiler to do the linking, but -Wl,-e,foo won't work being passed to the C compiler as -e foo. I only added this handling for -Wl,-e because I just written the /entry: part for MSVC (which I knew was needed).
Hmm. Given that you can't specify the entry point at the moment on mingw-w64, I'm tempted to remove this bit of code and just add a comment that you can't change the entrypoint on mingw-w64?
There was a problem hiding this comment.
Oh - coffee kicks in! I remember how this works - the -Wl, translation to -link is a shim to allow common options to pass through. You can specify the entry point on mingw-w64, it's just that you have to say -link -Wl,-e,entrypoint at which point the code above does work as intended!
| - GPR#146: Take the entrypoint (main, wmainCRTStartup, etc.) into account when | ||
| determining the modules which will be linked. For mingw-w64, select crt2u.o | ||
| instead of crt2.o if -link -municode is specified (David Allsopp) |
There was a problem hiding this comment.
This should be moved in the section above.
Presently on trunk and - as far as I can tell - since OCaml 3.11, in Cygwin64:
This is strange, since ocaml/ocaml@27780d9#diff-3c8eb806a6be5e7baa5af9546b7e12cdfa1220daae562235a450f87b93dd06e7 in OCaml 3.12 ensures that
debugger.ois linked into OCaml programs precisely to prevent this problem. The symbol is indeed present:the issue is that it is not included in the flexlink export table:
$ PATH=opt/bin:$PATH ./boot/ocamlrun.exe ./ocamlopt.exe -nostdlib -I ./stdlib -I otherlibs/dynlink -I utils -I parsing -I typing -I bytecomp -I file_formats -I lambda -I middle_end -I middle_end/closure -I middle_end/flambda -I middle_end/flambda/base_types -I asmcomp -I driver -I toplevel -I tools -I runtime -I otherlibs/dynlink -I otherlibs/str -I otherlibs/systhreads -I otherlibs/unix -I otherlibs/runtime_events -g -linkall -I toplevel/native -o ocamlnat.exe compilerlibs/ocamlcommon.cmxa compilerlibs/ocamloptcomp.cmxa compilerlibs/ocamlbytecomp.cmxa otherlibs/dynlink/dynlink.cmxa compilerlibs/ocamltoplevel.cmxa toplevel/topstart.cmx -cclib -show-exports | fgrep caml_debugger_in_useThe reason is that while
-lasmrunis passed to flexlink, the objects passed on the command line give flexlink no reason to linkstartup_nat.n.o, which would then causedebugger.n.oto be considered and consequently these symbols to be added to the export table.The fundamental fix here is that when linking an executable, flexlink now considers the entry point when closing over the required list of objects. For Cygwin, this fix is quite simple as it suffices to consider linking
main. Cygwin's gcc does linkcrt0.o, but the full mechanism is technically a bit more involved. This doesn't matter, though, because being a Posix system, the entrypoint is alwaysmain(notwmainorWinMain/wWinMain, etc.).For both MSVC and mingw-w64, the fix is a little more complex as, being non-Posix, there's not a strict requirement for the entrypoint to be
main. For mingw-w64, the entrypoint ismainCRTStartup, but whether that callsmainorwmainis determined by-municodewhich selects between usingcrt2.oorcrt2u.oas the startup object. MSVC is affected both by the/ENTRYand/SUBSYSTEMlinker options, which select between one ofmainCRTStartup,wmainCRTStartup,WinMainCRTStartuporwWinMainCRTStartup.MSVCRT.libcontains each of those symbols in a separate object each of which then has an import reference to eithermain,wmain,WinMainorwWinMainas required. Since OCaml 4.06, OCaml therefore uses-municodefor mingw-w64 and/ENTRY:wMainCRTStartupfor MSVC.This leads to the main part of this PR - the entrypoint for mingw-w64 and MSVC is therefore defined not in one of the objects or libraries passed on the command line (i.e. in
libasmrun.a), but in one of the default libraries (eithercrt2u.oorMSVCRT.lib). The problem is that while these libraries are scanned, they are not analysed when closing over the objects which need to be linked. This is correct (the default libraries are assumed to be being linked in both executable and DLL) - but the objects should be considered in case they import symbols which do come from the objects and libraries passed on the command line. The changes here therefore mean that for mingw-w64,mainCRTStartupgets resolved tocrt2u.o. That module importswmainwhich then causesmain.n.ofromlibasmrun.ato be linked and, consequentlystartup_nat.n.oand hencedebugger.n.o. This PR happens to be an alternate fix (or, rather, workaround) for ocaml/ocaml#13520.