[lld] r363078 - lld-link: Reject more than one resource .obj file

Hans Wennborg via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 23 05:54:48 PDT 2019


Merged to release_90 in r369752.

On Tue, Jun 11, 2019 at 5:19 PM Nico Weber via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
>
> Author: nico
> Date: Tue Jun 11 08:22:28 2019
> New Revision: 363078
>
> URL: http://llvm.org/viewvc/llvm-project?rev=363078&view=rev
> Log:
> lld-link: Reject more than one resource .obj file
>
> Users are exepcted to pass all .res files to the linker, which then
> merges all the resource in all .res files into a tree structure and then
> converts the final tree structure to a .obj file with .rsrc$01 and
> .rsrc$02 sections and then links that.
>
> If the user instead passes several .obj files containing such resources,
> the correct thing to do would be to have custom code to merge the trees
> in the resource sections instead of doing normal section merging -- but
> link.exe rejects if multiple resource obj files are passed in with
> LNK4078, so let lld-link do that too instead of silently writing broken
> .rsrc sections in that case.
>
> The only real way to run into this is if users manually convert .res
> files to .obj files by running cvtres and then handing the resulting
> .obj files to lld-link instead, which in practice likely never happens.
>
> (lld-link is slightly stricter than link.exe now: If link.exe is passed
> one .obj file created by cvtres, and a .res file, for some reason it
> just emits a warning instead of an error and outputs strange looking
> data. lld-link now errors out on mixed input like this.)
>
> One way users could accidentally run into this is the following
> scenario: If a .res file is passed to lib.exe, then lib.exe calls
> cvtres.exe on the .res file before putting it in the output .lib.
> (llvm-lib currently doesn't do this.)
> link.exe's /wholearchive seems to only add obj files referenced from the
> static library index, but lld-link current really adds all files in the
> archive. So if lld-link /wholearchive is used with .lib files produced
> by lib.exe and .res files were among the files handed to lib.exe, we
> previously silently produced invalid output, but now we error out.
>
> link.exe's /wholearchive semantics on the other hand mean that it
> wouldn't load the resource object files from the .lib file at all.
> Since this scenario is probably still an unlikely corner case,
> the difference in behavior here seems fine -- and lld-link might have to
> change to use link.exe's /wholearchive semantics in the future anyways.
>
> Vaguely related to PR42180.
>
> Differential Revision: https://reviews.llvm.org/D63109
>
> Added:
>     lld/trunk/test/COFF/multiple-resource-objs.test
> Modified:
>     lld/trunk/COFF/Driver.cpp
>     lld/trunk/COFF/DriverUtils.cpp
>     lld/trunk/COFF/InputFiles.cpp
>     lld/trunk/COFF/InputFiles.h
>     lld/trunk/test/CMakeLists.txt
>
> Modified: lld/trunk/COFF/Driver.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/Driver.cpp?rev=363078&r1=363077&r2=363078&view=diff
> ==============================================================================
> --- lld/trunk/COFF/Driver.cpp (original)
> +++ lld/trunk/COFF/Driver.cpp Tue Jun 11 08:22:28 2019
> @@ -971,6 +971,32 @@ static void parsePDBAltPath(StringRef Al
>    Config->PDBAltPath = Buf;
>  }
>
> +/// Check that at most one resource obj file was used.
> +/// Call after ObjFile::Instances is complete.
> +static void diagnoseMultipleResourceObjFiles() {
> +  // The .rsrc$01 section in a resource obj file contains a tree description
> +  // of resources.  Merging multiple resource obj files would require merging
> +  // the trees instead of using usual linker section merging semantics.
> +  // Since link.exe disallows linking more than one resource obj file with
> +  // LNK4078, mirror that.  The normal use of resource files is to give the
> +  // linker many .res files, which are then converted to a single resource obj
> +  // file internally, so this is not a big restriction in practice.
> +  ObjFile *ResourceObjFile = nullptr;
> +  for (ObjFile *F : ObjFile::Instances) {
> +    if (!F->IsResourceObjFile)
> +      continue;
> +
> +    if (!ResourceObjFile) {
> +      ResourceObjFile = F;
> +      continue;
> +    }
> +
> +    error(toString(F) +
> +          ": more than one resource obj file not allowed, already got " +
> +          toString(ResourceObjFile));
> +  }
> +}
> +
>  // In MinGW, if no symbols are chosen to be exported, then all symbols are
>  // automatically exported by default. This behavior can be forced by the
>  // -export-all-symbols option, so that it happens even when exports are
> @@ -1812,6 +1838,9 @@ void LinkerDriver::link(ArrayRef<const c
>    if (Config->DoGC)
>      markLive(Symtab->getChunks());
>
> +  // Needs to happen after the last call to addFile().
> +  diagnoseMultipleResourceObjFiles();
> +
>    // Identify identical COMDAT sections to merge them.
>    if (Config->DoICF) {
>      findKeepUniqueSections();
>
> Modified: lld/trunk/COFF/DriverUtils.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/DriverUtils.cpp?rev=363078&r1=363077&r2=363078&view=diff
> ==============================================================================
> --- lld/trunk/COFF/DriverUtils.cpp (original)
> +++ lld/trunk/COFF/DriverUtils.cpp Tue Jun 11 08:22:28 2019
> @@ -697,6 +697,7 @@ void checkFailIfMismatch(StringRef Arg,
>  }
>
>  // Convert Windows resource files (.res files) to a .obj file.
> +// Does what cvtres.exe does, but in-process and cross-platform.
>  MemoryBufferRef convertResToCOFF(ArrayRef<MemoryBufferRef> MBs) {
>    object::WindowsResourceParser Parser;
>
>
> Modified: lld/trunk/COFF/InputFiles.cpp
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.cpp?rev=363078&r1=363077&r2=363078&view=diff
> ==============================================================================
> --- lld/trunk/COFF/InputFiles.cpp (original)
> +++ lld/trunk/COFF/InputFiles.cpp Tue Jun 11 08:22:28 2019
> @@ -206,6 +206,10 @@ SectionChunk *ObjFile::readSection(uint3
>    if (Def)
>      C->Checksum = Def->CheckSum;
>
> +  // link.exe uses the presence of .rsrc$01 for LNK4078, so match that.
> +  if (Name == ".rsrc$01")
> +    IsResourceObjFile = true;
> +
>    // CodeView sections are stored to a different vector because they are not
>    // linked in the regular manner.
>    if (C->isCodeView())
> @@ -667,7 +671,8 @@ void ObjFile::initializeFlags() {
>  // types of external files: Precomp/PCH OBJs, when compiling with /Yc and /Yu.
>  // And PDB type servers, when compiling with /Zi. This function extracts these
>  // dependencies and makes them available as a TpiSource interface (see
> -// DebugTypes.h).
> +// DebugTypes.h). Both cases only happen with cl.exe: clang-cl produces regular
> +// output even with /Yc and /Yu and with /Zi.
>  void ObjFile::initializeDependencies() {
>    if (!Config->Debug)
>      return;
>
> Modified: lld/trunk/COFF/InputFiles.h
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/COFF/InputFiles.h?rev=363078&r1=363077&r2=363078&view=diff
> ==============================================================================
> --- lld/trunk/COFF/InputFiles.h (original)
> +++ lld/trunk/COFF/InputFiles.h Tue Jun 11 08:22:28 2019
> @@ -162,10 +162,13 @@ public:
>    // precompiled object. Any difference indicates out-of-date objects.
>    llvm::Optional<uint32_t> PCHSignature;
>
> -  // Tells whether this file was compiled with /hotpatch
> +  // Whether this is an object file created from .res files.
> +  bool IsResourceObjFile = false;
> +
> +  // Whether this file was compiled with /hotpatch.
>    bool HotPatchable = false;
>
> -  // Whether the object was already merged into the final PDB or not
> +  // Whether the object was already merged into the final PDB.
>    bool MergedIntoPDB = false;
>
>    // If the OBJ has a .debug$T stream, this tells how it will be handled.
>
> Modified: lld/trunk/test/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/CMakeLists.txt?rev=363078&r1=363077&r2=363078&view=diff
> ==============================================================================
> --- lld/trunk/test/CMakeLists.txt (original)
> +++ lld/trunk/test/CMakeLists.txt Tue Jun 11 08:22:28 2019
> @@ -34,8 +34,8 @@ configure_lit_site_cfg(
>  set(LLD_TEST_DEPS lld)
>  if (NOT LLD_BUILT_STANDALONE)
>    list(APPEND LLD_TEST_DEPS
> -    FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-dis
> -    llvm-dwarfdump llvm-lib llvm-mc llvm-nm llvm-objcopy llvm-objdump
> +    FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-cvtres
> +    llvm-dis llvm-dwarfdump llvm-lib llvm-mc llvm-nm llvm-objcopy llvm-objdump
>      llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt yaml2obj
>      )
>  endif()
>
> Added: lld/trunk/test/COFF/multiple-resource-objs.test
> URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/COFF/multiple-resource-objs.test?rev=363078&view=auto
> ==============================================================================
> --- lld/trunk/test/COFF/multiple-resource-objs.test (added)
> +++ lld/trunk/test/COFF/multiple-resource-objs.test Tue Jun 11 08:22:28 2019
> @@ -0,0 +1,11 @@
> +# RUN: llvm-cvtres /out:%t_resource.obj %S/Inputs/resource.res
> +# RUN: llvm-cvtres /out:%t_id.obj %S/Inputs/id.res
> +# RUN: not lld-link /out:%t.exe /dll /noentry %t_id.obj %t_resource.obj 2>&1 | \
> +# RUN:     FileCheck --check-prefix=TWOOBJ %s
> +
> +TWOOBJ: error: {{.*}}_resource.obj: more than one resource obj file not allowed, already got {{.*}}_id.obj
> +
> +# RUN: not lld-link /out:%t.exe /dll /noentry %S/Inputs/id.res %t_resource.obj 2>&1 | \
> +# RUN:     FileCheck --check-prefix=OBJRES %s
> +
> +OBJRES: error: internal .obj file created from .res files: more than one resource obj file not allowed, already got {{.*}}_resource.obj
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits


More information about the llvm-commits mailing list