-
Notifications
You must be signed in to change notification settings - Fork 159
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
Upstreaming some archive / coff short import writing code? #591
Comments
Unless @bjorn3 wants
Short import object write support would be fine, since we have a parser for it already. |
Sounds good. I've got plenty of stuff left in that PR to go, but I can look at getting a short import writing PR opened here in the meantime, which I assume should basically try to look like Object write? |
So the code for the short import is just this: pub(crate) fn write_short_import(
data: &mut DataWriter,
dll_name: &str,
name: &&str,
ordinal_or_hint: Option<std::primitive::u16>,
) {
data.write_pod(&ImportObjectHeaderUnaligned {
sig1: u16(IMAGE_FILE_MACHINE_UNKNOWN),
sig2: u16(IMPORT_OBJECT_HDR_SIG2),
version: u16(0),
machine: u16(IMAGE_FILE_MACHINE_AMD64),
time_date_stamp: u32(0),
size_of_data: u32((name.len() + 1 + dll_name.len() + 1) as u32),
ordinal_or_hint: u16(ordinal_or_hint.unwrap_or_default()),
name_type: u16(IMPORT_OBJECT_CODE << IMPORT_OBJECT_TYPE_SHIFT
| IMPORT_OBJECT_NAME << IMPORT_OBJECT_NAME_SHIFT),
});
data.write_c_str(name);
data.write_c_str(dll_name);
} I'm actually not sure how useful it is really going to be to add a small function like this to |
I was thinking mostly for consistency wrt the machine name type etc., moving to
If I feel particularly sad about all the code in that PR I can always make my own crate (with classy ladies and Uno) 😊 |
(Possibly should be a new issue, but I'm still happy to PR any changes you think are appropriate to get this working with Hmm. Took a stab at using
Which if I dump it using
But
Not sure why that's what MSVC does, but I blindly copied the structure, and it works. so 🤷 (To clarify, this is so the linker will build a valid import directory entry for the DLL, using the I tried a few different approaches, but nothing seems to successfully link: using values like I tried inlining the section definitions:
but that just crashes on link and Am I missing something? |
Yeah that looks like a combination of fields that we don't support yet. Don't expect |
One option may be to add a |
The best documentation I could find is just the I'm now thinking that This would also be a good place to add higher level helpers for creating the complete objects, as well as the short imports (so the equivalent of things like your If you want, I can do the work to create |
Yeah, theres' some GNU code out there, etc., but that seems to be only only official documentation for linkers. I've been mostly just trying to match what MSVC does. I'm not sure that |
These are a bug; they aren't actually common symbols. Instead, they are section symbols for sections that are defined in another member of the archive. #592 improves the read side of this.
However, I don't know why |
Yeah, I was planning to poke around to see what works before defining a public API. I'm particularly curious why MSVC has the null thunks and null directory entry in a separate member: my understanding was that linkers operate on the section level so I can't figure out why they would have it be that complicated, $4 and $5 seem like they should be fine to be defined in the same never. Something about ordering or merging, perhaps? (But there's no COMDATs...) |
So: $6 being SECTION instead of STATIC makes the executable fail on load with:
$6 is the DLL name, so that makes some sense... but not why it would just disappear when the others don't (everything is still in the emitted .lib and parses fine, to be clear) On the other hand, changing $2 to STATIC seems to work fine. The docs are shockingly worthless - less than worthless even - here:
🤦♂️ Interestingly, moving the thunk sections $4 and $5 into the main directory member and removing the UNDEF references work fine ... but only when you drop the EXTERNAL (I guess the directory entry is magic to support both a SECTION/STATIC symbol and an EXTERNAL symbol?). No such luck on the NULL_DIRECTORY_ENTRY. Presumably this is because this is the only library defining imports for the dll_name, but not the only import library, so the linker can't only pick the one. That sort of answers why there needs to be three members too: so that they can be referenced by EXTERNAL symbols and duplicates null thunk members or null directory entries can be dropped when merging libraries? |
Now for the fun bit downstream of figuring out all this again, but for |
I think each DLL has its own null thunk (shouldn't ever be duplicates), but there is only one null directory (duplicates are dropped). So it makes sense that there might be a reason why it needs to be separate, but I still don't know why exactly. |
I've started implementing |
Thanks, yeah! Sorry I wasn't clearer about your earlier suggestion to do so: I don't want to step on any toes if you have a preferred API. I've been focusing on figuring out what else needs to be done to get my PR over the line, and while it's a bit ugly, the current code doesn't block that. I'm now a lot more confident about what the import library API using this would ideally look like though: if you have an API surface you expect to implement I can get that up in it's own repo (and maybe crate?) so you can end to end of you like. |
The code I'm writing won't know anything about import libraries. I'll modify |
#595 adds a COFF writer, and I've partially converted your PR in philipc/rustc_codegen_cranelift@a8e5804 (untested). The main difference from your writer is that it supports streaming the output, so it needs to reserve file ranges up front instead of mutating headers later. Review is welcome. |
Cool, I'll take a look this weekend. |
So I've got a branch rebased completely onto the merged code in #595 now: https://github.com/simonbuchan/rustc_codegen_cranelift/tree/raw_dylib_object_write I think something like the I've got a very little bit of reading it back in In theory a short import is just shorthand for a coff file with a symbol export mapped to an |
Heh, nah I'm missing something there. How is that code related to
Ideally you should be able to use
That sounds like something we should fix. Technically it's a breaking change though... You should be able to use
Yeah that makes sense. We can consider doing that if it's useful. |
I simply mean in terms of being a structure that you can read and write, rather than the low level read/write. But that would probably just be the impl Object stuff I referred to at the end.
Oh, is that for short imports? Damn.
Yeah. Honestly the whole
That's what I thought, but it was yelling at me. I might have just been screwing it up though? Probably just missing the lifetime parameter and misreading the error. |
Ah I see. So basically add write capability to
We're not copying anything, just pointing at it. Alignment is a property of the type and rust doesn't allow unaligned pointers. So the only way I can see to allow you to pick at use-site is to use different types, and I don't want that. The goal was that you shouldn't ever need to enable the In hindsight, I'm not sure that the performance benefit is worth the complexity cost. For now, you can enable the |
I see! You could have the unaligned read method return a copy, without the ref it would be automatically aligned. Probably more expensive and uglier to use than unconditionally using unaligned access. The bigger issue with aligned access is the data is probably being read from a In my case, I didn't feel it appropriate to add the unaligned feature to rustc_backend_cranelift in my first PR, especially since it seems like they deliberately disabled it, but who knows 🤷 |
The unaligned feature is not intentionally disabled. Wasm support is though. Note that ar_archive_writer already enables the unaligned feature anyway. |
FYI, |
In that case I expect there's nothing more to be done here. |
Howdy!
I've got some code for writing Windows dll import libraries in a PR over here: rust-lang/rustc_codegen_cranelift#1414 - some of it seems like it would be useful to upstream here, with some work to improve the UX, testing, and polishing.
In particular, it has:
ar
orar_archive_writer
's current public API.ar_archive_writer
might be a better path, given the much more heavily tested code.write::coff
code that I missed the existence of 😅 - though maybe there's still something salvageable thereAnd even the overall goal of writing DLL import libs seems like it might be in scope?
I'd be happy to work to get these up to your standard if you're interested.
The text was updated successfully, but these errors were encountered: