Skip to content

Windows support#1653

Draft
n1ght-hunter wants to merge 13 commits intowild-linker:mainfrom
n1ght-hunter:dev/window-support
Draft

Windows support#1653
n1ght-hunter wants to merge 13 commits intowild-linker:mainfrom
n1ght-hunter:dev/window-support

Conversation

@n1ght-hunter
Copy link

@n1ght-hunter n1ght-hunter commented Mar 6, 2026

A very much WIP windows support.
Currently you can link a very simple windows program with just test-pe

@n1ght-hunter n1ght-hunter marked this pull request as draft March 6, 2026 13:51
@n1ght-hunter n1ght-hunter changed the title New PR Windows support Mar 6, 2026
@davidlattimore
Copy link
Member

Nice work! If you'd like to send PRs for any abstraction work, that could be good. Just be sure to tell me which bit of abstraction you want do so that we avoid duplication. I guess one logical one to start with might be Args. From a look through the changes here, my initial comments are that for consistency with the other associated types, I'd probably call the associated type Args rather than ArgsType. I'd also be tempted to define a trait for it rather than putting all the methods to query the args on ObjectFile. Although if there are methods that need to use associated types from ObjectFile, then putting those methods there would make sense.

@n1ght-hunter
Copy link
Author

Nice work! If you'd like to send PRs for any abstraction work, that could be good. Just be sure to tell me which bit of abstraction you want do so that we avoid duplication. I guess one logical one to start with might be Args. From a look through the changes here, my initial comments are that for consistency with the other associated types, I'd probably call the associated type Args rather than ArgsType. I'd also be tempted to define a trait for it rather than putting all the methods to query the args on ObjectFile. Although if there are methods that need to use associated types from ObjectFile, then putting those methods there would make sense.

There are a couple things i think it would be good to have some input in before submitting a pr.

  • What do you think about the use a Args with deref impl for T. this allows shared common args and shared default values plus QOL for access(dont required calling functions and has direct access to values). This could be replaced with a trait instead which has methods to access each of the shared args.

  • What it the thoughts on the target arg. this is non standard and as far as i know no other linker does this. llvm did discuss doing it but i dont think ever did. personally i would like for this to be used and think it should be the standard for cross platform linkers. and then build on top of it so if target isnt set we use name of exe which llvm currently does i.e. lld vs link-ld etc and if that isnt used then fallback to system default e.g. target elf on linux.

  • I really dont like my current approach with the run! macro to handle args. i think perhaps that the crate::run function and run in sub process perhaps should be generic over args and in the main.rs branch on args.

  • I think there needs to be a better trait for abstracting over target. currently i have created TargetFormat which i dont like the name but im bad at naming. also its not clear to me what the platform trait should be an abstraction over. currently its very much caters to elf. should this be changed. perhaps platform should modified instead of createding TargetFormat. but we still need a way to go from args to platform in a generic way.

Any feedback on these which be very welcome. also would it be fine to have a pr say adding windows args + windows compilation that just panics if you target windows/pe?

@davidlattimore
Copy link
Member

  • What do you think about the use a Args with deref impl for T. this allows shared common args and shared default values plus QOL for access(dont required calling functions and has direct access to values). This could be replaced with a trait instead which has methods to access each of the shared args.

I assume having Args<T> deref to T would require less changes. In that case, I'd be OK with it, with the proviso that we might at some point experiment with making Args be a trait instead to see how it compares.

  • What it the thoughts on the target arg.

Having a flag in addition to the LLVM approach of switching based on argv[0] seems good to me. It's weird having to scan the arguments to determine how to parse the arguments, but I don't see any alternatives. We could also check some environment variable. Possibly as the lowest priority check before defaulting based on the platform we're running on.

  • I really dont like my current approach with the run! macro to handle args. i think perhaps that the crate::run function and run in sub process perhaps should be generic over args and in the main.rs branch on args.

I haven't yet looking into what you're doing there enough yet to have thoughts on alternatives.

  • I think there needs to be a better trait for abstracting over target.

Yeah, I'm not entirely happy with the Platform / ObjectFile relationship at the moment. I'm not sure what best way to structure it is though. My main annoyance at the moment is the invariant lifetimes that arise from it.

  • currently i have created TargetFormat which i dont like the name but im bad at naming.

Yeah, naming is hard. I'm not sure about the naming of Platform. I keep on wanting to use the word platform to refer to Linux/Mac/Windows. Need a better name for Arch+OS.

  • also its not clear to me what the platform trait should be an abstraction over.

The idea as it current stands is that it's file-format + CPU architecture. So PeFile would implement ObjectFile, then the platform would be something like PeX86_64 with possible support for PeAarch64 at some point.

  • currently its very much caters to elf.

Yeah. My rough plan was make it less ELF-specific as we go. For the trait to be shared between the different file formats, it to some extent needs to be a superset of what those file formats need. There might be scope to have an elf-specific trait provided it's only needs to be used from elf-specific code (e.g. in elf_writer.rs). At one point I did have an ElfPlatform trait that inherited from Platform<File = elf::File>, but it turned out that the compiler wasn't smart enough to unify some types when I did that, so I ended up getting rid of it.

Any feedback on these which be very welcome.

I've only looked at bits of the PR so far. One thing I did notice was that it doesn't seem to use the layout phase. I haven't found what it's doing instead. My intention is for the layout phase to become generic enough that it can be used for other platforms. A lot of the things the linker needs to do are in layout. e.g. garbage collection, figuring out how bit each section needs to be, assigning addresses. So I expect that eventually we'd want to use it for windows too.

also would it be fine to have a pr say adding windows args + windows compilation that just panics if you target windows/pe?

There's a PR in progress for making wild compile for windows - #1629. So I wouldn't want to take that work away for that contributor while they're still working on it.

As for adding parsing of windows args without the rest of the required support for windows, I'd be fine with that. Ideally if code needs to be moved and edited, it'd be good if those operations can be done in separate PRs, or at least separate commits in one PR (although we now always squash on merge), since that makes the diffs easier to review.

I guess something else that needs to be figured out is module structure. I've thus far avoided having submodules, but I accept that at some point it might be necessary to put some code in a subdirectory of src. I'm not quite sure why I'm so reticent to have subdirectories. I've used them in other Rust projects. Perhaps I just like having all the files on the one level. Probably I need to get over it. But it'd be good to have somewhat of a plan. e.g. do we put all the elf stuff in one directory and all the pe stuff in another.

@n1ght-hunter
Copy link
Author

yes it would be good to sort out how you think modules should be handled. i dont really see anyway around having them and personally i like them. what is needed though is how the structuring should be done.
which there is a couple of options i see.
firstly wether to have a high level os/target modules or kinda per modules os/target i.e. src/elf and src/pe or something like src/layout/elf.rs and src/layout/pe.rs. i think the later option is better and pushs more for reused code in like src/layout.rs or src/layout/mod.rs. then other main thing is to decide do u want src/layout.rs or src/layout/mod.rs. i dont really have much of a preference there

@davidlattimore
Copy link
Member

I'm inclined to go with src/layout.rs rather than src/layout/mod.rs for two reasons. Firstly, it avoids the need to rename existing files and secondly, it probably shows up better in editors that give preference to the filename over the directory in which the file resides.

If we have elf-specific layout code as a submodule of layout, how would we reference that code? At the moment, I've got most of the elf-specific layout code in elf.rs, which means the relevant types can be referenced from the elf::File implementation of the ObjectFile trait. I'm not sure what that would look like if the elf-specific layout code was under the layout module. Perhaps it would be fine, I'm just having a hard time imagining it.

@n1ght-hunter
Copy link
Author

sounds good. i think for the second part the best way is just build it out and see what happens and refactor later. i feel like hindsight will probably play a big role

@mati865
Copy link
Member

mati865 commented Mar 7, 2026

LLD allows changing the target via combination of -flavor and -m args. Although semantics aren't great.

First is the distinction whether to use GNU ld or link.exe style args, aka flavor (there are also mac and wasm flavors but not relavant here). This is based on -flavor with fallback on the LLD's binary name. Note, -flavor must be passed as the first argument. https://github.com/llvm/llvm-project/blob/e830ee80063531fdfb1273cc112634b62926c66f/lld/Common/DriverDispatcher.cpp#L31

Windows targets can use either style, link for MSVC and clang-cl compilers, and GNU for GCC and Clang compilers targeting MinGW triples. I have no experience with link flavor after this point, but for GNU one you can change the target via emulation arg (-m, in Wild's code that maps to arch fileld in Args). https://github.com/llvm/llvm-project/blob/e830ee80063531fdfb1273cc112634b62926c66f/lld/Common/DriverDispatcher.cpp#L40

MinGW driver handles GNU style args and converts them into link style args: https://github.com/llvm/llvm-project/blob/4d08284157d09ce6104f0753f1dbf5adc43c113d/lld/MinGW/Driver.cpp#L620
It also supports link style args via -Xlink arg.

There is also an elephant in this room: quoting and escaping command line args. Because of Windows stupid decision to use escape character as path separator, for example C:\foo\bar (nowadays C/foo/bar also works but it's less common) you cannot parse arguments uniformly for all targets or even hardcode quoting style depending on the target. There is an argument for changing quoting style for all Windows targets, wasm and even for ELF: https://github.com/llvm/llvm-project/blob/4d08284157d09ce6104f0753f1dbf5adc43c113d/lld/ELF/DriverUtils.cpp#L78

Personally I don't care about MSVC toolchains, but I can help with MinGW part if we decide on whether and how to support it. Ability to build Windows binaries on Linux could also help when developing Windows specific parts.

@mati865
Copy link
Member

mati865 commented Mar 7, 2026

As per https://github.com/wild-linker/wild/blob/b95e0f8461e1b8fa2cc07467f49e83cd0ca978a2/CONTRIBUTING.md#llm--ai-use-policy could you disclose whether (and how if the previous answer was positive) you used AI for this PR?

@davidlattimore
Copy link
Member

Note that the policy currently doesn't require disclosure of AI use, except for written communication, or if there are bits of code / changes to code that the submitter doesn't fully understand themselves.

@mati865
Copy link
Member

mati865 commented Mar 8, 2026

My point is generating code via LLMs usually means the author at least partially doesn't understand proposed changes. If AI was used, then I'd ask for explicit statement that author reviewed and understands the changes, before taking deeper look into the code.

@n1ght-hunter
Copy link
Author

LLD allows changing the target via combination of -flavor and -m args. Although semantics aren't great.

First is the distinction whether to use GNU ld or link.exe style args, aka flavor (there are also mac and wasm flavors but not relavant here). This is based on -flavor with fallback on the LLD's binary name. Note, -flavor must be passed as the first argument. https://github.com/llvm/llvm-project/blob/e830ee80063531fdfb1273cc112634b62926c66f/lld/Common/DriverDispatcher.cpp#L31

my personal goal would be to support target triple as a set all flag to specify the target info then also support the more standard -m -flavor flags etc that will overide the target triple if used. this gives the best of both world IMO.

MinGW driver handles GNU style args and converts them into link style args: https://github.com/llvm/llvm-project/blob/4d08284157d09ce6104f0753f1dbf5adc43c113d/lld/MinGW/Driver.cpp#L620 It also supports link style args via -Xlink arg.

i like i currently have we should just support on windows targets at the same time in the parser. the logic is basiclly start with "-" or "/" and flag name.lower_case() == flag name. which means you can write the parser builder logic onces and have it work on both flag types.

There is also an elephant in this room: quoting and escaping command line args. Because of Windows stupid decision to use escape character as path separator, for example C:\foo\bar (nowadays C/foo/bar also works but it's less common) you cannot parse arguments uniformly for all targets or even hardcode quoting style depending on the target. There is an argument for changing quoting style for all Windows targets, wasm and even for ELF: https://github.com/llvm/llvm-project/blob/4d08284157d09ce6104f0753f1dbf5adc43c113d/lld/ELF/DriverUtils.cpp#L78

I haven't run into this being an issue yet but haven't tested a heap.

Personally I don't care about MSVC toolchains, but I can help with MinGW part if we decide on whether and how to support it. Ability to build Windows binaries on Linux could also help when developing Windows specific parts.

building to target MSVC isnt too bad on linux for rust u can just use https://github.com/rust-cross/cargo-xwin

@n1ght-hunter
Copy link
Author

As per https://github.com/wild-linker/wild/blob/b95e0f8461e1b8fa2cc07467f49e83cd0ca978a2/CONTRIBUTING.md#llm--ai-use-policy could you disclose whether (and how if the previous answer was positive) you used AI for this PR?

Sure i use LLM's (Claude code mainly) for various parts. I normally use it to do research and find links for reading reading material on whatever im working on. Also use it to write parts of the code base i think it can do a good job of. i.e. i want to move fields from say linux/elf struct onto common/shared struct. In general i wouldn't put a pr up for review unless i had read every line written and decided it wasn't slop. unless its simple changes that would be enforced by a some form a automated checking like rustc compile time checks.

@n1ght-hunter
Copy link
Author

My point is generating code via LLMs usually means the author at least partially doesn't understand proposed changes. If AI was used, then I'd ask for explicit statement that author reviewed and understands the changes, before taking deeper look into the code.

If you want to do this. Which in general i would agree with as there is too much slop code these days. You should probably come up with a well worded question that makes more sense for the various ways that "AI" is used. Like using a AI autocomplete like is completely different from used in Agent mode which is completely different from AI used to research or ask questions. I mean you could even argue that any search engine request in google.com etc is AI and has been for years. Anyways my point being you should come up with a template or better worded question that covers the use case better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants