This is an archive of the discontinued LLVM Phabricator instance.

Implement COFF emission for parsed Windows Resource ( .res) files.
ClosedPublic

Authored by ecbeckmann on Jun 7 2017, 9:25 PM.

Details

Summary

Add the WindowsResourceCOFFWriter class for producing the final COFF after all parsing is done.

Diff Detail

Repository
rL LLVM

Event Timeline

ecbeckmann created this revision.Jun 7 2017, 9:25 PM
ruiu added inline comments.Jun 8 2017, 4:01 PM
llvm/include/llvm/Object/WindowsResource.h
52–54 ↗(On Diff #101850)

I don't think it is a good practice to declare a new type in a header in an anonymous namespace because (I believe it is intended to be an internal data type but) it is visible from everywhere that includes this file. You can just use std::vector<std::vector<T>>, no? It is actually more readable than Table<T> as the former type is obvious.

58 ↗(On Diff #101850)

Enum classes must start with an uppercase letter. Also, = 0 is redundant.

71 ↗(On Diff #101850)

You can just do

return Suffix->Version >> 16;
74 ↗(On Diff #101850)

and

return Suffix->Version;
llvm/lib/Object/WindowsResource.cpp
137 ↗(On Diff #101850)

Remove this blank line.

387–392 ↗(On Diff #101850)

I doubt you actually want to fill the timestamp field of the output file. If you do that, any build is no longer reproducible. You probably want to leave it zero.

llvm/tools/llvm-cvtres/llvm-cvtres.cpp
115–118 ↗(On Diff #101850)
bool Verbose = InputArgs.hasArg(OPT_VERBOSE);
ecbeckmann updated this revision to Diff 101982.Jun 8 2017, 4:54 PM
ecbeckmann marked 6 inline comments as done.

Fix bug with reloc symbol name being printed in decimal, not hex.

Also fixed some readability bugs.

ecbeckmann added inline comments.
llvm/include/llvm/Object/WindowsResource.h
52–54 ↗(On Diff #101850)

Okay, whichever is most readable.

llvm/lib/Object/WindowsResource.cpp
387–392 ↗(On Diff #101850)

Hmm isn't the timestamp important for incremental linking to work? I don't think it's important for builds to be reproducible, since we are testing our output with the llvm-readobj tool.

ruiu added inline comments.Jun 8 2017, 5:01 PM
llvm/lib/Object/WindowsResource.cpp
391 ↗(On Diff #101982)

Incremental linking sees file itself's timestamp instead of a timestamp field inside a file, no?

Reproducible build is generally important in many use cases, and you don't want to break that property unless breaking it is absolutely necessary. It is so convenient if you can always create an identical output from the same source tree.

majnemer added inline comments.
llvm/lib/Object/WindowsResource.cpp
391 ↗(On Diff #101982)

The MS linker actually uses the time in the file. I learned this the hard way getting LLVM obj files compatible with LINK.exe

zturner added inline comments.Jun 8 2017, 5:07 PM
llvm/include/llvm/Object/WindowsResource.h
127–128 ↗(On Diff #101982)

Maybe you can return ArrayRef<std::vector<uint8_t>> here? Similarly for other function.

llvm/lib/Object/WindowsResource.cpp
137–143 ↗(On Diff #101982)

I don't think emplace_back is a win here, but it makes the code a little mroe confusing. Can you change this to push_back?

164–165 ↗(On Diff #101982)

If it's not a string node and it's not a data node, then what is it?

165 ↗(On Diff #101982)

Can you just initialize these inline in the class definition so we don't need these here?

170–178 ↗(On Diff #101982)

What happens if someone passes false here? Is it even valid to have a data node with a version and characteristics?

These two constructors are really confusing. What do you think about making the constructors private and then adding static functions

std::unique_ptr<TreeNode> createDataNode(uint16_t Major, uint16_t Minor, uint32_t Characteristics);

etc?

311 ↗(On Diff #101982)

ArrayRef?

zturner added inline comments.Jun 8 2017, 5:08 PM
llvm/lib/Object/WindowsResource.cpp
391 ↗(On Diff #101982)

Shouldn't we do whatever MS does?

ruiu added inline comments.Jun 8 2017, 5:11 PM
llvm/lib/Object/WindowsResource.cpp
391 ↗(On Diff #101982)

If that's needed, then well, we have to do that.

ecbeckmann updated this revision to Diff 101985.Jun 8 2017, 6:17 PM
ecbeckmann marked 4 inline comments as done.

Refactor constructors for clarity.

Use ArrayRefs instead.

ecbeckmann added inline comments.Jun 8 2017, 6:18 PM
llvm/lib/Object/WindowsResource.cpp
164–165 ↗(On Diff #101982)

There are two types of nodes: those that point to data, and those that point to children nodes. In the later case, the node can be identified by either a string or an integer id. So if it's not a string node and not a data node, it's a non-data node identified by an integer id.

I should probably make this distinction more clear in the constructors. I've changed it so that one constructor is always used for creating non-data nodes, an accepts a flag for making it a string node. The other constructor makes only data nodes.

170–178 ↗(On Diff #101982)

Hmmm intuitively it would seem that only data nodes should have version and characteristics, however I've had trouble verifying this and I haven't been able to generate a .res file where the version and characteristics are set to anything other than zero. For now I think it's safe to assume that only nodes containing data would have a version and characteristic for that data specified.

I've tried to make things more clear in the constructors by having one used only for making data nodes and one for all others.

zturner added inline comments.Jun 8 2017, 6:22 PM
llvm/lib/Object/WindowsResource.cpp
170–178 ↗(On Diff #101982)

But now the constructor doesn't really express its intent clearly. A user can't tell from looking that that the 3 argument version is for data nodes etc. How about making the constructor private and having:

static std::unique_ptr<TreeNode> creteStringNode(StringRef Str);
static std::unique_ptr<TreeNode> creteStringNode(uint32_t StringId);
static std::unique_ptr<TreeNode> createDataNode(uint16_t Major, uint16_t Minor, uint32_t Characteristics);
majnemer added inline comments.Jun 8 2017, 7:19 PM
llvm/lib/Object/WindowsResource.cpp
391 ↗(On Diff #101982)

I bet they support the /Brepro flag that CL.exe has. If they support it we could have it too and fill it with whatever value they do. IIRC, they use 0xFFFFFFFF in CL to make it so that it always looks "new".

ecbeckmann updated this revision to Diff 101991.Jun 8 2017, 8:26 PM
ecbeckmann marked an inline comment as done.

Refactored parser + node classes to make more sense, and hide interfaces that other classes should never access.

ecbeckmann added inline comments.Jun 8 2017, 8:26 PM
llvm/lib/Object/WindowsResource.cpp
170–178 ↗(On Diff #101982)

Okay I've added these functions to clarify when each type of node is made.

In fact, nothing outside of the class should be able to create new nodes. This is because creating new nodes relies on being able to keep the data and string table indexes in sync with the actual data and strings in the order they are read. I've made all non-const functions private and added WindowsResourceParser as a friend class, since really TreeNode is a class it uses internally and they know how each other function.

zturner accepted this revision.Jun 9 2017, 9:12 AM
This revision is now accepted and ready to land.Jun 9 2017, 9:12 AM
This revision was automatically updated to reflect the committed changes.
llvm/trunk/test/tools/llvm-cvtres/parse.test