-
Notifications
You must be signed in to change notification settings - Fork 33
Ensure the entrypoint is taken into account when computing the export table #146
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -725,7 +725,7 @@ let needed imported defined resolve_alias resolve_alternate obj = | |||||||||||
| StrSet.empty | ||||||||||||
| obj.symbols | ||||||||||||
|
|
||||||||||||
| let build_dll link_exe output_file files exts extra_args = | ||||||||||||
| let build_dll link_exe output_file files exts extra_args_string = | ||||||||||||
| let main_pgm = link_exe <> `DLL in | ||||||||||||
|
|
||||||||||||
| (* fully resolve filenames, eliminate duplicates *) | ||||||||||||
|
|
@@ -767,7 +767,7 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| in | ||||||||||||
| (* Collect all the available symbols, including those defined | ||||||||||||
| in default libraries *) | ||||||||||||
| let defined, from_imports, resolve_alias, resolve_alternate = | ||||||||||||
| let defined, from_imports, resolve_alias, resolve_alternate, collected = | ||||||||||||
| let aliases = Hashtbl.create 16 in | ||||||||||||
| let alternates = Hashtbl.create 16 in | ||||||||||||
| let defined = ref StrSet.empty in | ||||||||||||
|
|
@@ -836,14 +836,16 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
|
|
||||||||||||
| and collect_file fn = | ||||||||||||
| if not (Hashtbl.mem collected (String.lowercase_ascii fn)) then begin | ||||||||||||
| Hashtbl.replace collected (String.lowercase_ascii fn) (); | ||||||||||||
| debug 2 "** open: %s" fn; | ||||||||||||
| collect_defined fn (Lib.read fn) | ||||||||||||
| end | ||||||||||||
|
|
||||||||||||
| and collect_defined fn = function | ||||||||||||
| | `Obj obj -> collect_defined_obj obj | ||||||||||||
| | `Obj obj -> | ||||||||||||
| Hashtbl.replace collected (String.lowercase_ascii fn) [fn, obj]; | ||||||||||||
| collect_defined_obj obj | ||||||||||||
| | `Lib (objs,imports) -> | ||||||||||||
| Hashtbl.replace collected (String.lowercase_ascii fn) objs; | ||||||||||||
| List.iter (fun (_, obj) -> collect_defined_obj obj) objs; | ||||||||||||
| List.iter | ||||||||||||
| (fun (s,_) -> | ||||||||||||
|
|
@@ -854,12 +856,7 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| ) | ||||||||||||
| imports | ||||||||||||
| in | ||||||||||||
| List.iter | ||||||||||||
| (fun (fn,x) -> | ||||||||||||
| Hashtbl.replace collected (String.lowercase_ascii fn) (); | ||||||||||||
| collect_defined fn x | ||||||||||||
| ) | ||||||||||||
| files; | ||||||||||||
| List.iter (fun (fn,x) -> collect_defined fn x) files; | ||||||||||||
| if !use_default_libs then List.iter (fun fn -> collect_file (find_file fn)) !default_libs; | ||||||||||||
| List.iter (fun fn -> collect_file (find_file fn)) exts; | ||||||||||||
|
|
||||||||||||
|
|
@@ -869,13 +866,13 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| if !machine = `x64 then add_def "__ImageBase" | ||||||||||||
| else add_def "___ImageBase"; | ||||||||||||
|
|
||||||||||||
| !defined, !from_imports, (Hashtbl.find aliases), (Hashtbl.find alternates) | ||||||||||||
| !defined, !from_imports, (Hashtbl.find aliases), (Hashtbl.find alternates), collected | ||||||||||||
| in | ||||||||||||
|
|
||||||||||||
| (* Determine which objects from the given libraries should be linked | ||||||||||||
| in. First step: find the mapping (symbol -> object) for these | ||||||||||||
| objects. *) | ||||||||||||
| let defined_in = | ||||||||||||
| let defined_in, default_libs = | ||||||||||||
| let defined_in = Hashtbl.create 16 in | ||||||||||||
| let def_in_obj fn (objname, obj) = | ||||||||||||
| List.iter | ||||||||||||
|
|
@@ -893,29 +890,36 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| ) | ||||||||||||
| obj.symbols | ||||||||||||
| in | ||||||||||||
| List.iter | ||||||||||||
| (fun (fn,objs) -> | ||||||||||||
| if !explain then Printf.printf "Scanning lib %s\n%!" fn; | ||||||||||||
| List.iter (def_in_obj fn) objs | ||||||||||||
| ) | ||||||||||||
| libs; | ||||||||||||
| Hashtbl.find defined_in | ||||||||||||
| let scan (fn,objs) = | ||||||||||||
| if !explain then Printf.printf "Scanning lib %s\n%!" fn; | ||||||||||||
| List.iter (def_in_obj fn) objs | ||||||||||||
| in | ||||||||||||
| let default_libs = | ||||||||||||
| List.fold_right | ||||||||||||
| (fun fn acc -> | ||||||||||||
| let fn = find_file fn in | ||||||||||||
| scan (fn, Hashtbl.find collected (String.lowercase_ascii fn)); | ||||||||||||
| StrSet.add fn acc) | ||||||||||||
| (if !use_default_libs then !default_libs else []) | ||||||||||||
| StrSet.empty | ||||||||||||
| in | ||||||||||||
| List.iter scan libs; | ||||||||||||
| Hashtbl.find defined_in, default_libs | ||||||||||||
| in | ||||||||||||
|
|
||||||||||||
| let imported_from_implib = ref StrSet.empty in | ||||||||||||
| let imported = ref StrSet.empty in | ||||||||||||
|
|
||||||||||||
| let imports obj = | ||||||||||||
| let n = needed imported defined resolve_alias resolve_alternate obj in | ||||||||||||
| imported_from_implib := StrSet.union !imported_from_implib (StrSet.inter n from_imports); | ||||||||||||
| let undefs = StrSet.diff n defined in | ||||||||||||
| StrSet.filter | ||||||||||||
| (fun s -> | ||||||||||||
| match check_prefix "__imp_" s with | ||||||||||||
| | Some _ -> false | ||||||||||||
| | None -> s <> "environ" (* special hack for Cygwin64 *) | ||||||||||||
| ) | ||||||||||||
| undefs | ||||||||||||
| undefs, StrSet.inter n from_imports | ||||||||||||
| in | ||||||||||||
|
|
||||||||||||
| (* Second step: transitive closure, starting from given objects *) | ||||||||||||
|
|
@@ -981,7 +985,7 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| in | ||||||||||||
|
|
||||||||||||
| let dll_exports = ref StrSet.empty in | ||||||||||||
| let rec link_obj fn obj = | ||||||||||||
| let record_exports obj = | ||||||||||||
| List.iter | ||||||||||||
| (fun sym -> | ||||||||||||
| if Symbol.is_defin sym && exportable sym.sym_name | ||||||||||||
|
|
@@ -990,7 +994,9 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| obj.symbols; | ||||||||||||
|
|
||||||||||||
| dll_exports := List.fold_left (fun accu x -> StrSet.add x accu) | ||||||||||||
| !dll_exports (collect_dllexports obj); | ||||||||||||
| !dll_exports (collect_dllexports obj) | ||||||||||||
| in | ||||||||||||
| let rec link_obj fn obj = | ||||||||||||
| StrSet.iter | ||||||||||||
| (fun s -> | ||||||||||||
| if StrSet.mem s !exported then () | ||||||||||||
|
|
@@ -1007,16 +1013,75 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| (needed imported defined resolve_alias resolve_alternate obj) | ||||||||||||
|
|
||||||||||||
| and link_libobj (libname,objname,obj) = | ||||||||||||
| let default = StrSet.mem libname default_libs in | ||||||||||||
| if Hashtbl.mem libobjects (libname,objname) then () | ||||||||||||
| else (Hashtbl.replace libobjects (libname,objname) (obj,imports obj); | ||||||||||||
| else (let imports, from_imports = imports obj in | ||||||||||||
| let imports = if default then StrSet.empty else imports in | ||||||||||||
| Hashtbl.replace libobjects (libname,objname) (obj,imports); | ||||||||||||
| if not default then begin | ||||||||||||
| imported_from_implib := StrSet.union !imported_from_implib from_imports; | ||||||||||||
| record_exports obj | ||||||||||||
| end; | ||||||||||||
| link_obj (Printf.sprintf "%s(%s)" libname objname) obj) | ||||||||||||
| in | ||||||||||||
|
|
||||||||||||
| let entrypoint = | ||||||||||||
| if not main_pgm then | ||||||||||||
| None | ||||||||||||
| else | ||||||||||||
| match !toolchain with | ||||||||||||
| | `CYGWIN64 -> | ||||||||||||
| Some "main" | ||||||||||||
| | `MINGW | `MINGW64 -> begin | ||||||||||||
| let entry_point s = | ||||||||||||
| String.length s > 7 && String.sub s 0 7 = "-Wl,-e," | ||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Isn't Lines 281 to 285 in ab8161f
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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 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?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds reasonable!
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh - coffee kicks in! I remember how this works - the |
||||||||||||
| in | ||||||||||||
| try | ||||||||||||
| let s = List.find entry_point !extra_args in | ||||||||||||
| Some (String.sub s 7 (String.length s - 7)) | ||||||||||||
| with Not_found -> | ||||||||||||
| Some "mainCRTStartup" | ||||||||||||
| end | ||||||||||||
| | `MSVC | `MSVC64 -> begin | ||||||||||||
| let entry_point s = | ||||||||||||
| String.length s > 7 && String.lowercase_ascii (String.sub s 0 7) = "/entry:" | ||||||||||||
| in | ||||||||||||
| try | ||||||||||||
| let s = List.find entry_point !extra_args in | ||||||||||||
| Some (String.sub s 7 (String.length s - 7)) | ||||||||||||
| with Not_found -> | ||||||||||||
| if !subsystem = "windows" then | ||||||||||||
| Some "WinMainCRTStartup" | ||||||||||||
| else | ||||||||||||
| Some "mainCRTStartup" | ||||||||||||
| end | ||||||||||||
| | `LIGHTLD | `GNAT | `GNAT64 -> | ||||||||||||
| None | ||||||||||||
| in | ||||||||||||
| let () = | ||||||||||||
| match entrypoint with | ||||||||||||
| | None -> () | ||||||||||||
| | Some entrypoint -> | ||||||||||||
| try | ||||||||||||
| let (libname, objname, _) as o = defined_in entrypoint in | ||||||||||||
| if !explain then | ||||||||||||
| Printf.printf "%s(%s) because of entrypoint %s\n%!" libname objname | ||||||||||||
| entrypoint; | ||||||||||||
| link_libobj o | ||||||||||||
| with Not_found -> | ||||||||||||
| if !explain then | ||||||||||||
| Printf.printf "Entrypoint %s not found\n%!" entrypoint | ||||||||||||
| in | ||||||||||||
| let redirect = Hashtbl.create 16 in | ||||||||||||
| List.iter | ||||||||||||
| (fun (fn, obj) -> | ||||||||||||
| let default = StrSet.mem fn default_libs in | ||||||||||||
| let imps, from_imports = imports obj in | ||||||||||||
| if not default then begin | ||||||||||||
| imported_from_implib := StrSet.union !imported_from_implib from_imports; | ||||||||||||
| record_exports obj | ||||||||||||
| end; | ||||||||||||
| link_obj fn obj; | ||||||||||||
| let imps = imports obj in | ||||||||||||
| if StrSet.is_empty imps then () | ||||||||||||
| else Hashtbl.replace redirect fn (close_obj fn imps obj); | ||||||||||||
| ) objs; | ||||||||||||
|
|
@@ -1142,24 +1207,24 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| being an empty file. *) | ||||||||||||
| let c = open_out implib in output_string c "x"; close_out c; | ||||||||||||
| let _impexp = add_temp (Filename.chop_suffix implib ".lib" ^ ".exp") in | ||||||||||||
| let extra_args = | ||||||||||||
| if !custom_crt then "/nodefaultlib:LIBCMT /nodefaultlib:MSVCRT " ^ extra_args | ||||||||||||
| else "msvcrt.lib " ^ extra_args | ||||||||||||
| let extra_args_string = | ||||||||||||
| if !custom_crt then "/nodefaultlib:LIBCMT /nodefaultlib:MSVCRT " ^ extra_args_string | ||||||||||||
| else "msvcrt.lib " ^ extra_args_string | ||||||||||||
| in | ||||||||||||
|
|
||||||||||||
| let extra_args = | ||||||||||||
| if !machine = `x64 then (Printf.sprintf "/base:%s " !base_addr) ^ extra_args else extra_args | ||||||||||||
| let extra_args_string = | ||||||||||||
| if !machine = `x64 then (Printf.sprintf "/base:%s " !base_addr) ^ extra_args_string else extra_args_string | ||||||||||||
| in | ||||||||||||
|
|
||||||||||||
| let extra_args = | ||||||||||||
| let extra_args_string = | ||||||||||||
| (* FlexDLL doesn't process .voltbl sections correctly, so don't allow the linker | ||||||||||||
| to process them. *) | ||||||||||||
| let command = | ||||||||||||
| if Sys.win32 then link ^ " /nologo /? | findstr EMITVOLATILEMETADATA > NUL" | ||||||||||||
| else link ^ " /nologo '/?' | grep -iq emitvolatilemetadata >/dev/null" in | ||||||||||||
| if Sys.command command = 0 then | ||||||||||||
| "/EMITVOLATILEMETADATA:NO " ^ extra_args | ||||||||||||
| else extra_args | ||||||||||||
| "/EMITVOLATILEMETADATA:NO " ^ extra_args_string | ||||||||||||
| else extra_args_string | ||||||||||||
| in | ||||||||||||
|
|
||||||||||||
| (* Flexdll requires that all images (main programs and all the DLLs) are | ||||||||||||
|
|
@@ -1187,7 +1252,7 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| (Filename.quote output_file) | ||||||||||||
| !subsystem | ||||||||||||
| files descr | ||||||||||||
| extra_args | ||||||||||||
| extra_args_string | ||||||||||||
| | `CYGWIN64 -> | ||||||||||||
| let def_file = | ||||||||||||
| if main_pgm then "" | ||||||||||||
|
|
@@ -1209,7 +1274,7 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| descr | ||||||||||||
| files | ||||||||||||
| def_file | ||||||||||||
| extra_args | ||||||||||||
| extra_args_string | ||||||||||||
| | `MINGW | `MINGW64 | `GNAT | `GNAT64 -> | ||||||||||||
| let def_file = | ||||||||||||
| if main_pgm then "" | ||||||||||||
|
|
@@ -1233,7 +1298,7 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| files | ||||||||||||
| def_file | ||||||||||||
| (if !implib then "-Wl,--out-implib=" ^ Filename.quote (Filename.chop_extension output_file ^ ".a") else "") | ||||||||||||
| extra_args | ||||||||||||
| extra_args_string | ||||||||||||
| | `LIGHTLD -> | ||||||||||||
| no_merge_manifest := true; | ||||||||||||
| let ld = Option.value !Cmdline.use_linker ~default:"ld" in | ||||||||||||
|
|
@@ -1246,7 +1311,7 @@ let build_dll link_exe output_file files exts extra_args = | |||||||||||
| descr | ||||||||||||
| files | ||||||||||||
| (if !implib then "--out-implib " ^ Filename.quote (Filename.chop_extension output_file ^ ".a") else "") | ||||||||||||
| extra_args | ||||||||||||
| extra_args_string | ||||||||||||
| in | ||||||||||||
| debug ~dry_mode 1 "+ %s" cmd; | ||||||||||||
| if not !dry_mode then begin | ||||||||||||
|
|
@@ -1423,8 +1488,14 @@ let setup_toolchain () = | |||||||||||
| with Not_found -> () | ||||||||||||
| in | ||||||||||||
| default_libs := "-lmingw32" :: "-lgcc" :: !default_libs; | ||||||||||||
| if !exe_mode = `EXE then default_libs := "crt2.o" :: !default_libs | ||||||||||||
| else default_libs := "dllcrt2.o" :: !default_libs | ||||||||||||
| if not (List.mem "-nostartfiles" !extra_args) then begin | ||||||||||||
| if !exe_mode = `EXE then | ||||||||||||
| if List.mem "-municode" !extra_args then | ||||||||||||
| default_libs := "crt2u.o" :: !default_libs | ||||||||||||
| else | ||||||||||||
| default_libs := "crt2.o" :: !default_libs | ||||||||||||
| else default_libs := "dllcrt2.o" :: !default_libs | ||||||||||||
| end | ||||||||||||
| in | ||||||||||||
| match !toolchain with | ||||||||||||
| | _ when !builtin_linker -> | ||||||||||||
|
|
||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be moved in the section above.