On ARM64X, symbol names alone are ambiguous as they may refer to either
a native or an EC symbol. Append '(EC symbol)' or '(native symbol)' in
diagnostic messages to distinguish them.
If the ECSYMBOLS section is missing in the archive, the archive could be
either a native-only ARM64 or x86_64 archive. Check the machine type of
the object containing a symbol to determine which symbol table to use.
In hybrid images, the PE header references a single IAT for both native
and EC views, merging entries where possible. When merging isn't
feasible, different imports are grouped together, and ARM64X relocations
are emitted as needed.
This is a follow-up to #120452 in a way.
Since lld/COFF does not yet insert all defined in an obj file before all
undefineds (ELF and MachO do this, see #67445 and things linked from
there), it's possible that:
1. We add an obj file a.obj
2. a.obj contains an undefined that's in b.obj, causing b.obj to be
added
3. b.obj contains an undefined that's in a part of a.obj that's not yet
in the symbol table, causing a recursive load of a.obj, which adds the
symbols in there twice, leading to duplicate symbol errors.
For normal archives, `ArchiveFile::addMember()` has a `seen` check to
prevent this. For start-lib lazy objects, we can just check if the
archive is still lazy at the recursive call.
This bug is similar to issue #59162.
(Eventually, we'll probably want to do what the MachO and ELF ports do.)
Includes a test that caused duplicate symbol diagnostics before this
code change.
ecb5ea6a26 tried to fix cases when LLD
links what seems to be import library header objects from MSVC. However,
the fix seems incorrect; the review at https://reviews.llvm.org/D133627
concluded that if this (treating this kind of symbol as a common symbol)
is what link.exe does, it's fine.
However, this is most probably not what link.exe does. The symbol
mentioned in the commit message of
ecb5ea6a26 would be a common symbol with a
size of around 3 GB; this is not what might have been intended.
That commit tried to avoid running into the error ".idata$4 should not
refer to special section 0"; that issue is fixed for a similar style of
section symbols in 4a4a8a1476.
Therefore, revert ecb5ea6a26 and extend
the fix from 4a4a8a1476 to also work for
the section symbols in MSVC generated import libraries.
The main detail about them, is that for symbols of type
IMAGE_SYM_CLASS_SECTION, the Value field is not an offset, but it is an
optional set of flags, corresponding to the Characteristics of the
section header (although it may be empty).
This is a reland of a previous version of this commit, earlier merged in
9457418e66 / #122811. The previous version
failed tests when run with address sanitizer. The issue was that the
synthesized coff_symbol_generic object actually will be used to access a
full coff_symbol16 or coff_symbol32 struct, see
DefinedCOFF::getCOFFSymbol. Therefore, we need to make a copy of the
full size of either of them.
ecb5ea6a26 tried to fix cases when LLD
links what seems to be import library header objects from MSVC. However,
the fix seems incorrect; the review at https://reviews.llvm.org/D133627
concluded that if this (treating this kind of symbol as a common symbol)
is what link.exe does, it's fine.
However, this is most probably not what link.exe does. The symbol
mentioned in the commit message of
ecb5ea6a26 would be a common symbol with a
size of around 3 GB; this is not what might have been intended.
That commit tried to avoid running into the error ".idata$4 should not
refer to special section 0"; that issue is fixed for a similar style of
section symbols in 4a4a8a1476.
Therefore, revert ecb5ea6a26 and extend
the fix from 4a4a8a1476 to also work for
the section symbols in MSVC generated import libraries.
The main detail about them, is that for symbols of type
IMAGE_SYM_CLASS_SECTION, the Value field is not an offset, but it is an
optional set of flags, corresponding to the Characteristics of the
section header (although it may be empty).
When LLD links against an import library (for the regular, short import
libraries), it doesn't actually link in the header/trailer object files
at all, but synthesizes new corresponding data structures into the right
sections.
If the whole of such an import library is forced to be linked, e.g. with
the -wholearchive: option, we actually end up linking in those
header/trailer objects. The header objects contain a construct which LLD
fails to handle; previously we'd error out with the error ".idata$4
should not refer to special section 0".
Within the import library header object, in the import directory we have
relocations towards the IAT (.idata$4 and .idata$5), but the header
object itself doesn't contain any data for those sections.
In the case of GNU generated import libraries, the header objects
contain zero length sections .idata$4 and .idata$5, with relocations
against them. However in the case of LLVM generated import libraries,
the sections .idata$4 and .idata$5 are not included in the list of
sections. The symbol table does contain section symbols for these
sections, but without any actual associated section. This can probably
be seen as a declaration of an empty section.
If the header/trailer objects of a short import library are linked
forcibly and we also reference other functions in the library, we end up
with two import directory entries for this DLL, one that gets
synthesized by LLD, and one from the actual header object file. This is
inelegant, but should be acceptable.
While it would seem unusual to link import libraries with the
-wholearchive: option, this can happen in certain scenarios.
Rust builds libraries that contain relevant import libraries bundled
along with compiled Rust code as regular object files, all within one
single archive. Such an archive can then end up linked with the
-wholarchive: option, if build systems decide to use such an option for
including static libraries.
This should fix https://github.com/msys2/MINGW-packages/issues/21017.
This works for the header/trailer object files in import libraries
generated by LLVM; import libraries generated by MSVC are vaguely
different. ecb5ea6a26 did an attempt at
fixing the issue for MSVC generated libraries, but it's not entirely
correct, and isn't enough for making things work for that case.
This already worked without /wholearchive; now it works with it too.
(Only for thin archives containing relative file names, matching the ELF
and Mach-O ports.)
The addFile implementation does not rely on the SymbolTable object. With
#119294, the symbol table for input files is determined during the
construction of the objects representing them. To clarify that
relationship, this change moves the implementation from the SymbolTable
class to the LinkerDriver class.
If foo.obj is eagerly loaded (due to a prior undef referencing one if
its symbols) and has more than one symbol, we used to assert:
SymbolTable::addLazyObject() for the first symbol would set `lazy` to
false and load all symbols from the file, but the outer
ObjFile::parseLazy() loop would continue to run and call addLazyObject()
for the second symbol, which would assert.
Instead, just stop adding lazy symbols if the file got loaded for real
while adding a symbol.
(The ELF port has a similar early exit in `ObjFile<ELFT>::parseLazy()`.)
On hybrid ARM64X targets, ARM64 and ARM64EC input files operate in
separate namespaces and cannot reference each other. This change
introduces separate `SymbolTable` instances and associates each
`InputFile` with the appropriate table to reflect this behavior.
This change prepares for hybrid ARM64X support, which requires two
`SymbolTable` instances: one for native symbols and one for EC symbols.
In such cases, `config.machine` will remain ARM64X, while the
`SymbolTable` instances will store ARM64 and ARM64EC machine types.
This change prepares for the introduction of separate hybrid namespaces.
Hybrid images will require two `SymbolTable` instances, making it
necessary to associate `InputFile` objects with the relevant one.
Similar to #112319 for ELF. While there is some initial boilerplate, it
can simplify some call sites that use Twine, especially when a printed
element uses `ctx` or toString.
On ARM64EC, external function calls emit a pair of weak-dependency
aliases: `func` to `#func` and `#func` to the `func` guess exit thunk
(instead of a single undefined `func` symbol, which would be emitted on
other targets). Allow such aliases to be overridden by lazy archive
symbols, just as we would for undefined symbols.
Co-authored-by: Billy Laws <blaws05@gmail.com>
Anti-dependency symbols are allowed to be duplicated, with the first
definition taking precedence. If a regular weak alias is present, it is
preferred over an anti-dependency definition. Chaining anti-dependencies
is not allowed.
In addition to the auxiliary IAT, ARM64EC modules also contain a copy of
it. At runtime, the auxiliary IAT is filled with the addresses of actual
ARM64EC functions when possible. If patching is detected, the OS may use
the IAT copy to revert the auxiliary IAT, ensuring that the call checker
is used for calls to imported functions.
In addition to the regular IAT, ARM64EC also includes an auxiliary IAT.
At runtime, the regular IAT is populated with the addresses of imported
functions, which may be x86_64 functions or the export thunks of ARM64EC
functions. The auxiliary IAT contains versions of functions that are
guaranteed to be directly callable by ARM64 code.
The linker fills the auxiliary IAT with the addresses of `__impchk_`
thunks. These thunks perform a call on the IAT address using
`__icall_helper_arm64ec` with the target address from the IAT. If the
imported function is an ARM64EC function, the OS may replace the address
in the auxiliary IAT with the address of the ARM64EC version of the
function (not its export thunk), avoiding the runtime call checker for
better performance.
These thunks can be accessed using `__impchk_*` symbols, though they
are typically not called directly. Instead, they are used to populate the
auxiliary IAT. When the imported function is x86_64 (or an ARM64EC
function with a patched export thunk), the thunk is used to call it.
Otherwise, the OS may replace the thunk at runtime with a direct
pointer to the ARM64EC function to avoid the overhead.
For x86_64 callable functions, ARM64EC requires an entry thunk generated
by the compiler. The linker interprets .hybmp sections to associate
function chunks with their entry points and writes an offset to thunks
preceding function section contents.
Additionally, ICF needs to be aware of entry thunks to not consider
chunks to be equal when they have different entry thunks, and GC needs
to mark entry thunks together with function chunks.
I used a new SectionChunkEC class instead of storing entry thunks in
SectionChunk, following the guideline to keep SectionChunk as compact as
possible. This way, there is no memory usage increase on non-EC targets.
In addition to looking for dependent (input) PDB files next to the associated .OBJ file, we now also look into the output folder as well. This mimics MSVC link.exe behavior.
Fixes#94152
This allows handling importlibs produced by llvm-dlltool in #78772.
ARM64EC import libraries use it by default, but it's supported by MSVC
link.exe on other platforms too.
This also avoids assuming null-terminated input, like in #78769.
The export names are saved as StringRefs pointing into the COFF
directives. In the case of LTO objects, this can be memory allocated
that is owned by the LTO InputFile, which gets destructed when doing the
compilation.
In the case of LTO objects from an older version of LLVM, which require
being upgraded when loaded, the directives string gets destructed, while
when using LTO objects of a matching version (the common case), the
directives string points into memory that doesn't get destructed on LTO
compilation.
Test this by linking a bundled binary LTO object file, from an older
version of LLVM.
This fixes issue #78591, and downstream issue
https://github.com/mstorsjo/llvm-mingw/issues/392.
This shouldn't have any user visible effect, but makes the logic within
the linker implementation more explicit.
Note how DWARF debug info sections were retained even if enabling a link
with PDB info only; that behaviour is preserved.
This redoes the fix from 3ab6209a3f
differently, without the unwanted effect of preserving unnecessary
`__imp_` prefixed symbols.
If the referencing object is a regular object, the `__imp_` symbol will
have `isUsedInRegularObj` set on it from that already. If the
referencing object is an LTO object, we set `isUsedInRegularObj` for any
symbol starting with `__imp_`.
If the object file defining the `__imp_` symbol is a regular object, the
`isUsedInRegularObj` flag has no effect. If it is an LTO object, it
causes the symbol to be preserved.
In practice, all the Windows ARMNT IR objects show the architecture type
Thumb, not ARM.
Most other switch cases for architecture in lld/COFF check for and treat
`arm` and `thumb` equally.