Background
I’ve been looking into adding icons to Swift executables on Windows. The standard way is to compile the icon into a resource object file and pass it to the linker (-Xlinker icon.res). For technical reasons I wanted to instead add the icon after compilation, which is a standard approach used by many including Electron.
Tools such rcedit and Resource Hacker can generally be used to set the icons of pre-compiled Windows executable files. For the most part they also work fine on executables produced by Swift Package Manager, but they break a few developer tools such as Visual Studio’s dumpbin (with missing string table) and LLVM’s objdump (with other string table related errors).
After much investigation, it seems that the issue is that SwiftPM produces executable with trailing data attached (after the end of the main PE executable structure). This is known to mess up tools such as rcedit and Resource Hacker, because they of course can’t know how such trailing data is meant to be treated when they have to expand the PE structure; is the program expect the data to be after the PE structure? does is expect the data to be at a constant offset from the start of the file?
I haven’t yet figured out what the trailing data is, but it seems related to debug or symbol information, as it has a lot of symbol names closely packed together.
I’ve tried to remove this data through various official means; such as llvm-strip -x program.exe, and compiling the program with -c release (in the hopes that it was debug info) or -Xswiftc -debug-info-format=codeview (in the hopes that the data was specifically DWARF related). Those options did all change the size of the resulting executable but left that trailing data in place.
If I remove the trailing data then my relatively complicated program (which uses quite a few dynamic features of Swift) seems to function perfectly fine, leading me to think that the data is purely for debugging?
Interestingly, when I compile a test program with swiftc I don’t get the trailing data, which may in part be due to swiftc using link.exe from the Visual Studio toolchain instead of using lld-link.exe from the Swift toolchain like SwiftPM does.
Questions
- What is this trailing data?
- Should this trailing data be added as a section of the PE executable to better support PE editing tools such as rcedit and Resource Hacker? Or is there some technical reason forcing this to be trailing data?
During my testing I’ve been using the following Python script to analyse the executables and pull them apart.
import pefile
exe_file = "stripped-vvp.exe"
size = 0
with pefile.PE(exe_file, fast_load=True) as pe:
size = pe.OPTIONAL_HEADER.SizeOfHeaders
for section in pe.sections:
size += section.SizeOfRawData
print("PE size:", size)
print("True file size:", len(open(exe_file, "rb").read()))
contents = None
with open(exe_file, "rb") as f:
contents = f.read()
with open("out.bin", "wb") as outfile:
outfile.write(contents[size:])
with open("base.exe", "wb") as outfile:
outfile.write(contents[:size])
For my original use case, I’ve ended up just compiling the icon into the executable as a resource object file, which has some drawbacks because SwiftPM’s incremental builds don’t seem to like arbitrary custom linker arguments (quite understandably), but it’s okay for now. This investigation was more out of interest than necessity.