Skip to content
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

librsvg problem in clang #21017

Open
3 of 7 tasks
revelator opened this issue May 29, 2024 · 25 comments
Open
3 of 7 tasks

librsvg problem in clang #21017

revelator opened this issue May 29, 2024 · 25 comments
Labels
bug reported-upstream Issues reported or fixed in upstream repository

Comments

@revelator
Copy link
Contributor

Description / Steps to reproduce the issue

building librsvg with clang produces this error ->

ld.lld: error: librsvg_c_api.a(bcryptprimitives.dll): .idata$4 should not refer to special section 0
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Expected behavior

should produce the librsvg build like with gcc

Actual behavior

bugs out with the above error

Verification

Windows Version

MSYS_NT-10.0-26100

MINGW environments affected

  • MINGW64
  • MINGW32
  • UCRT64
  • CLANG64
  • CLANG32
  • CLANGARM64

Are you willing to submit a PR?

No response

@revelator revelator added the bug label May 29, 2024
@Biswa96
Copy link
Member

Biswa96 commented May 29, 2024

I can reproduce the issue with clang64.

@revelator
Copy link
Contributor Author

yeah not really sure whats going on there ???

@revelator
Copy link
Contributor Author

revelator commented May 29, 2024

looks like an invalid section in the bcryptprimitives export though it is not even part of the mingw-w64-abi only bcrypt.
seems it links directly to the dll but fails and it is not clear if it is a problem with the compiler or something else.

@revelator
Copy link
Contributor Author

ah i smell a mingw specific linker script sec investigating.

@mati865
Copy link
Collaborator

mati865 commented May 29, 2024

There are no linker/version scripts involved since LLD doesn't support them at all and would just error out.
The library is linked by Rust since rust-lang/rust#121337 by creating own import library through LLVM backend.

@revelator
Copy link
Contributor Author

exactly what i was after but yeah librsvg does not use a linker script so it seems to be something else going on.

@revelator
Copy link
Contributor Author

ok it is rust it seems, tried reverting to a previous version and now it builds...

@mati865
Copy link
Collaborator

mati865 commented May 29, 2024

How to reproduce this problem?
For me clean checkout of librsvg from git (commit b4d6f2071342ef5be36f25253a9bf1bf9277f8ec) and running with Rust from CLANG64 works:

$ cargo b
...
Finished `dev` profile [unoptimized + debuginfo] target(s) in 44.55s

$ cargo clean

$ cargo b -r
...
Finished `release` profile [optimized] target(s) in 51.56s

$ rustc -vV
rustc 1.78.0 (9b00956e5 2024-04-29) (Rev1, Built by MSYS2 project)
binary: rustc
commit-hash: 9b00956e56009bab2aa15d7bff10916599e3d6d6
commit-date: 2024-04-29
host: x86_64-pc-windows-gnu
release: 1.78.0
LLVM version: 18.1.4

and so does current nightly:

$ PKG_CONFIG_SYSROOT_DIR=/h/msys64/clang64/share/pkgconfig PKG_CONFIG_PATH=/h/msys64/clang64/bin/pkgconf.exe cargo b --target x86_64-pc-windows-gnullvm
...
Finished `dev` profile [unoptimized + debuginfo] target(s) in 55.57s

$ cargo clean

$ PKG_CONFIG_SYSROOT_DIR=/h/msys64/clang64/share/pkgconfig PKG_CONFIG_PATH=/h/msys64/clang64/bin/pkgconf.exe cargo b --target x86_64-pc-windows-gnullvm -r
...
Finished `release` profile [optimized] target(s) in 49.13s

$ rustc -vV
rustc 1.80.0-nightly (da159eb33 2024-05-28)
binary: rustc
commit-hash: da159eb331b27df528185c616b394bb0e1d2a4bd
commit-date: 2024-05-28
host: x86_64-pc-windows-gnu
release: 1.80.0-nightly
LLVM version: 18.1.6

@revelator
Copy link
Contributor Author

so some incompatibility between our version of rust/llvm and librsvg-2.58.0 ?

@revelator
Copy link
Contributor Author

revelator commented May 29, 2024

wait you are using the nightly version of rust ? im on 1.78 O_o

EDIT: nvm i see now

@mati865
Copy link
Collaborator

mati865 commented May 29, 2024

It does reproduce when building MSYS2 package (and with upstream code not newer than 2.58 using some special steps).

As I said previous on Discord something must be wrong with generated import libraries:

  • x86_64-pc-windows-gnullvm target/CLANG64 env:
$ nm /h/projects/MINGW-packages/mingw-w64-librsvg/src/build-CLANG64/.libs/librsvg_c_api.a | rg idata
00000000 i .idata$2
00000000 ? .idata$4
00000000 ? .idata$5
00000000 i .idata$6
00000000 i .idata$2
00000000 ? .idata$4
00000000 ? .idata$5
00000000 i .idata$6

$ objdump -t /h/projects/MINGW-packages/mingw-w64-librsvg/src/build-CLANG64/.libs/librsvg_c_api.a | rg idata
[ 1](sec  1)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$2
[ 2](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 3](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$4
[ 4](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$5
[ 1](sec  1)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$2
[ 2](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 3](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$4
[ 4](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$5
  • x86_64-pc-windows-gnu target:
$ nm target/release/liblibrsvg_c.a | grep idata
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$6
00000000 i .idata$7
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$6
00000000 i .idata$7
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$6
00000000 i .idata$7
00000000 i .idata$4
00000000 i .idata$5
00000000 i .idata$6
00000000 i .idata$7

$ objdump -t target/release/liblibrsvg_c.a | grep idata
[ 8](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$4
[10](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$5
[12](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$7
[10](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$2
[12](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[13](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[ 3](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$7
[ 4](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[ 5](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[ 6](sec  7)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 8](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$4
[10](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$5
[12](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$7
[10](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$2
[12](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[13](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[ 3](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$7
[ 4](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[ 5](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[ 6](sec  7)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 3](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$7
[ 4](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[ 5](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[ 6](sec  7)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 3](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$7
[ 4](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[ 5](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[ 6](sec  7)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6

EDIT: Naturally those symbols are present in prebuilt std library as they originate from there:

$ nm ~/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib | rg idata
00000000 i .idata$2
00000000 ? .idata$4
00000000 ? .idata$5
00000000 i .idata$6
00000000 i .idata$2
00000000 ? .idata$4
00000000 ? .idata$5
00000000 i .idata$6

$ objdump -t ~/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib | rg idata
[ 1](sec  1)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$2
[ 2](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 3](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$4
[ 4](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$5
[ 1](sec  1)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$2
[ 2](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 3](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$4
[ 4](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$5

@revelator
Copy link
Contributor Author

not sure if refering to me but im not on discord so i did not know :) but its being looked at thats what matters.

@mati865
Copy link
Collaborator

mati865 commented May 31, 2024

I'm afraid I'm not competent enough to understand what is going on here.

I've tried running objdump on those files but I don't even know what to look for (most of the differences are probably related to legacy vs short import lib format).
llvm-objdump -x of relevant sections:

  • gnu (import library crated with dlltool from Binutils):
Details
C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dllt.o):	file format coff-x86-64
rw-r--r-- 0/0    637 Thu Jan  1 01:00:00 1970 bcryptprimitives.dllt.o
architecture: x86_64
start address: 0x0000000000000000
Characteristics 0x5
relocations stripped
line numbers stripped

Time/Date               Thu Jan  1 01:00:00 1970

Sections:
Idx Name          Size     VMA              Type
  0 .text         00000000 0000000000000000 TEXT
  1 .data         00000000 0000000000000000 DATA
  2 .bss          00000000 0000000000000000 BSS
  3 .idata$4      00000008 0000000000000000 DATA
  4 .idata$5      00000008 0000000000000000 DATA
  5 .idata$7      00000018 0000000000000000 DATA

SYMBOL TABLE:
[ 0](sec -2)(fl 0x00)(ty   0)(scl  67) (nx 1) 0x00000000 .file
AUX fake
[ 2](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text
AUX scnlen 0x0 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[ 4](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[ 6](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[ 8](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$4
AUX scnlen 0x8 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[10](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$5
AUX scnlen 0x8 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[12](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$7
AUX scnlen 0x15 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[14](sec  6)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib_iname

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dllh.o):	file format coff-x86-64
rw-r--r-- 0/0    726 Thu Jan  1 01:00:00 1970 bcryptprimitives.dllh.o
architecture: x86_64
start address: 0x0000000000000000
Characteristics 0x4
line numbers stripped

Time/Date               Thu Jan  1 01:00:00 1970

Sections:
Idx Name          Size     VMA              Type
  0 .text         00000000 0000000000000000 TEXT
  1 .data         00000000 0000000000000000 DATA
  2 .bss          00000000 0000000000000000 BSS
  3 .idata$2      00000014 0000000000000000 DATA
  4 .idata$5      00000000 0000000000000000 DATA
  5 .idata$4      00000000 0000000000000000 DATA

SYMBOL TABLE:
[ 0](sec -2)(fl 0x00)(ty   0)(scl  67) (nx 1) 0x00000000 .file
AUX fake
[ 2](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 hname
[ 3](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 fthunk
[ 4](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .text
AUX scnlen 0x0 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[ 6](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .data
AUX scnlen 0x0 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[ 8](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .bss
AUX scnlen 0x0 nreloc 0 nlnno 0 checksum 0x0 assoc 0 comdat 0
[10](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 1) 0x00000000 .idata$2
AUX scnlen 0x14 nreloc 3 nlnno 0 checksum 0x0 assoc 0 comdat 0
[12](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[13](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[14](sec  4)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 _head_C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib
[15](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib_iname

RELOCATION RECORDS FOR [.idata$2]:
OFFSET           TYPE                     VALUE
0000000000000000 IMAGE_REL_AMD64_ADDR32NB .idata$4
000000000000000c IMAGE_REL_AMD64_ADDR32NB __C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib_iname
0000000000000010 IMAGE_REL_AMD64_ADDR32NB .idata$5

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dlls00000.o):	file format coff-x86-64
rw-r--r-- 0/0    659 Thu Jan  1 01:00:00 1970 bcryptprimitives.dlls00000.o
architecture: x86_64
start address: 0x0000000000000000
Characteristics 0x4
line numbers stripped

Time/Date               Thu Jan  1 01:00:00 1970

Sections:
Idx Name          Size     VMA              Type
  0 .text         00000008 0000000000000000 TEXT
  1 .data         00000000 0000000000000000 DATA
  2 .bss          00000000 0000000000000000 BSS
  3 .idata$7      00000004 0000000000000000 
  4 .idata$5      00000008 0000000000000000 
  5 .idata$4      00000008 0000000000000000 
  6 .idata$6      0000000e 0000000000000000 

SYMBOL TABLE:
[ 0](sec  1)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .text
[ 1](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .data
[ 2](sec  3)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .bss
[ 3](sec  4)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$7
[ 4](sec  5)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$5
[ 5](sec  6)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$4
[ 6](sec  7)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 7](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 ProcessPrng
[ 8](sec  5)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __imp_ProcessPrng
[ 9](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 _head_C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib

RELOCATION RECORDS FOR [.text]:
OFFSET           TYPE                     VALUE
0000000000000002 IMAGE_REL_AMD64_REL32    __imp_ProcessPrng

RELOCATION RECORDS FOR [.idata$7]:
OFFSET           TYPE                     VALUE
0000000000000000 IMAGE_REL_AMD64_ADDR32NB _head_C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib

RELOCATION RECORDS FOR [.idata$5]:
OFFSET           TYPE                     VALUE
0000000000000000 IMAGE_REL_AMD64_ADDR32NB .idata$6

RELOCATION RECORDS FOR [.idata$4]:
OFFSET           TYPE                     VALUE
0000000000000000 IMAGE_REL_AMD64_ADDR32NB .idata$6
  • gnullvm (import library created by Rust calling LLVM APIs):
Details
C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64
rw-r--r-- 0/0    397 Thu Jan  1 01:00:00 1970 bcryptprimitives.dll
architecture: x86_64
start address: 0x0000000000000000
Characteristics 0x0

Time/Date               Thu Jan  1 01:00:00 1970

Sections:
Idx Name          Size     VMA              Type
  0 .idata$2      00000014 0000000000000000 DATA
  1 .idata$6      00000015 0000000000000000 DATA

SYMBOL TABLE:
[ 0](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __IMPORT_DESCRIPTOR_bcryptprimitives
[ 1](sec  1)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$2
[ 2](sec  2)(fl 0x00)(ty   0)(scl   3) (nx 0) 0x00000000 .idata$6
[ 3](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$4
[ 4](sec  0)(fl 0x00)(ty   0)(scl  68) (nx 0) 0x00000000 .idata$5
[ 5](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __NULL_IMPORT_DESCRIPTOR
[ 6](sec  0)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 �bcryptprimitives_NULL_THUNK_DATA

RELOCATION RECORDS FOR [.idata$2]:
OFFSET           TYPE                     VALUE
000000000000000c IMAGE_REL_AMD64_ADDR32NB .idata$6
0000000000000000 IMAGE_REL_AMD64_ADDR32NB .idata$4
0000000000000010 IMAGE_REL_AMD64_ADDR32NB .idata$5

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64
rw-r--r-- 0/0    127 Thu Jan  1 01:00:00 1970 bcryptprimitives.dll
architecture: x86_64
start address: 0x0000000000000000
Characteristics 0x0

Time/Date               Thu Jan  1 01:00:00 1970

Sections:
Idx Name          Size     VMA              Type
  0 .idata$3      00000014 0000000000000000 DATA

SYMBOL TABLE:
[ 0](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 __NULL_IMPORT_DESCRIPTOR

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64
rw-r--r-- 0/0    172 Thu Jan  1 01:00:00 1970 bcryptprimitives.dll
architecture: x86_64
start address: 0x0000000000000000
Characteristics 0x0

Time/Date               Thu Jan  1 01:00:00 1970

Sections:
Idx Name          Size     VMA              Type
  0 .idata$5      00000008 0000000000000000 DATA
  1 .idata$4      00000008 0000000000000000 DATA

SYMBOL TABLE:
[ 0](sec  1)(fl 0x00)(ty   0)(scl   2) (nx 0) 0x00000000 �bcryptprimitives_NULL_THUNK_DATA

llvm-objdump -s of relevant sections:

  • gnu (import library crated with dlltool from Binutils):
Details
C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dllt.o):	file format coff-x86-64
Contents of section .idata$4:
 0000 00000000 00000000                    ........
Contents of section .idata$5:
 0000 00000000 00000000                    ........
Contents of section .idata$7:
 0000 62637279 70747072 696d6974 69766573  bcryptprimitives
 0010 2e646c6c 00000000                    .dll....

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dllh.o):	file format coff-x86-64
Contents of section .idata$2:
 0000 00000000 00000000 00000000 00000000  ................
 0010 00000000                             ....

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dlls00000.o):	file format coff-x86-64
Contents of section .text:
 0000 ff250000 00009090                    .%......
Contents of section .idata$7:
 0000 00000000                             ....
Contents of section .idata$5:
 0000 00000000 00000000                    ........
Contents of section .idata$4:
 0000 00000000 00000000                    ........
Contents of section .idata$6:
 0000 01005072 6f636573 7350726e 6700      ..ProcessPrng.
  • gnullvm (import library created by Rust calling LLVM APIs):
Details
C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64
Contents of section .idata$2:
 0000 00000000 00000000 00000000 00000000  ................
 0010 00000000                             ....
Contents of section .idata$6:
 0000 62637279 70747072 696d6974 69766573  bcryptprimitives
 0010 2e646c6c 00                          .dll.

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64
Contents of section .idata$3:
 0000 00000000 00000000 00000000 00000000  ................
 0010 00000000                             ....

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64
Contents of section .idata$5:
 0000 00000000 00000000                    ........
Contents of section .idata$4:
 0000 00000000 00000000                    ........

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format COFF-import-file

<literally empty, contains only two newlines>

llvm-objdump -D of relevant sections:

  • gnu (import library crated with dlltool from Binutils):
Details
C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dllt.o):	file format coff-x86-64

Disassembly of section .idata$4:

0000000000000000 <.idata$4>:
		...

Disassembly of section .idata$5:

0000000000000000 <.idata$5>:
		...

Disassembly of section .idata$7:

0000000000000000 <__C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib_iname>:
       0: 62 63 72 79 70               	<unknown>
       5: 74 70                        	je	0x77 <__C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib_iname+0x77>
       7: 72 69                        	jb	0x72 <__C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib_iname+0x72>
       9: 6d                           	insl	%dx, %es:(%rdi)
       a: 69 74 69 76 65 73 2e 64      	imull	$0x642e7365, 0x76(%rcx,%rbp,2), %esi # imm = 0x642E7365
      12: 6c                           	insb	%dx, %es:(%rdi)
      13: 6c                           	insb	%dx, %es:(%rdi)
      14: 00 00                        	addb	%al, (%rax)
      16: 00 00                        	addb	%al, (%rax)

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dllh.o):	file format coff-x86-64

Disassembly of section .idata$2:

0000000000000000 <_head_C__a__temp_msys64_tmp_rustc10hWNd_bcryptprimitives_lib>:
		...

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnu/lib/libstd-8e1d66ff2e108c97.rlib(bcryptprimitives.dlls00000.o):	file format coff-x86-64

Disassembly of section .text:

0000000000000000 <ProcessPrng>:
       0: ff 25 00 00 00 00            	jmpq	*(%rip)                 # 0x6 <ProcessPrng+0x6>
       6: 90                           	nop
       7: 90                           	nop

Disassembly of section .idata$7:

0000000000000000 <.idata$7>:
       0: 00 00                        	addb	%al, (%rax)
       2: 00 00                        	addb	%al, (%rax)

Disassembly of section .idata$5:

0000000000000000 <__imp_ProcessPrng>:
		...

Disassembly of section .idata$4:

0000000000000000 <.idata$4>:
		...

Disassembly of section .idata$6:

0000000000000000 <.idata$6>:
       0: 01 00                        	addl	%eax, (%rax)
       2: 50                           	pushq	%rax
       3: 72 6f                        	jb	0x74 <.idata$6+0x74>
       5: 63 65 73                     	movslq	0x73(%rbp), %esp
       8: 73 50                        	jae	0x5a <.idata$6+0x5a>
       a: 72 6e                        	jb	0x7a <.idata$6+0x7a>
       c: 67 00                        	<unknown>
  • gnullvm (import library created by Rust calling LLVM APIs):
Details
C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64

Disassembly of section .idata$2:

0000000000000000 <__IMPORT_DESCRIPTOR_bcryptprimitives>:
		...

Disassembly of section .idata$6:

0000000000000000 <.idata$6>:
       0: 62 63 72 79 70               	<unknown>
       5: 74 70                        	je	0x77 <.idata$6+0x77>
       7: 72 69                        	jb	0x72 <.idata$6+0x72>
       9: 6d                           	insl	%dx, %es:(%rdi)
       a: 69 74 69 76 65 73 2e 64      	imull	$0x642e7365, 0x76(%rcx,%rbp,2), %esi # imm = 0x642E7365
      12: 6c                           	insb	%dx, %es:(%rdi)
      13: 6c                           	insb	%dx, %es:(%rdi)
      14: 00                           	<unknown>

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64

Disassembly of section .idata$3:

0000000000000000 <__NULL_IMPORT_DESCRIPTOR>:
		...

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format coff-x86-64

Disassembly of section .idata$5:

0000000000000000 <�bcryptprimitives_NULL_THUNK_DATA>:
		...

Disassembly of section .idata$4:

0000000000000000 <.idata$4>:
		...

C:/Users/mateusz/.rustup/toolchains/nightly-x86_64-pc-windows-gnu/lib/rustlib/x86_64-pc-windows-gnullvm/lib/libstd-d31db6c27cb2af27.rlib(bcryptprimitives.dll):	file format COFF-import-file

<empty again>

llvm-readobj with various flags also didn't help.
The says about a symbol with section number: 0 but I couldn't find anything like that.

EDIT: Ah, I fixated on Number: from llvm-readobj -t:

  Section {
    Number: 2
    Name: .idata$4 (2E 69 64 61 74 61 24 34)
    VirtualSize: 0x0
    VirtualAddress: 0x0
    RawDataSize: 8
    PointerToRawData: 0x6C
    PointerToRelocations: 0x0
    PointerToLineNumbers: 0x0
    RelocationCount: 0
    LineNumberCount: 0
    Characteristics [ (0xC0400040)
      IMAGE_SCN_ALIGN_8BYTES (0x400000)
      IMAGE_SCN_CNT_INITIALIZED_DATA (0x40)
      IMAGE_SCN_MEM_READ (0x40000000)
      IMAGE_SCN_MEM_WRITE (0x80000000)
    ]
  }
]

but looks like llvm-readobj -s is the helpful one here:

  Symbol {
    Name: .idata$4
    Value: 0
    Section: IMAGE_SYM_UNDEFINED (0)
    BaseType: Null (0x0)
    ComplexType: Null (0x0)
    StorageClass: Section (0x68)
    AuxSymbolCount: 0
  }

Probably sec 0 from objdump means the same thing as IMAGE_SYM_UNDEFINED (0). Not sure how it helps though, at least I have something to report upstream.

@revelator
Copy link
Contributor Author

revelator commented May 31, 2024

yeah it also baffled me to no end... tried searching every freaking library or object file for a reference to where this might be comming from, took me all night and im still baffled (x_x). seems to work if i use an older version of llvm/clang together with an older rust build so it seems to be something recent.

i even tried making an import library for bcryptprimitives.dll to look at the section data for that spurious 0 but sadly found nothing so it does not seem to be from any imports. since it only started happening with recent rust id wager some upstream change might have caused this unintentionally but as mati points out it works in the nightly rust build so the confusion is even worse.

@mati865
Copy link
Collaborator

mati865 commented Jun 1, 2024

Not really minimal but at least self contained.
Can be reproduced by unpacking one of ZIPs (libstd is the smaller one) and running clang -shared -Wl,--whole-archive ./libstd-d31db6c27cb2af27.rlib or clang -shared -Wl,--whole-archive ./librsvg_c_api.a.

libstd-d31db6c27cb2af27.zip
librsvg_c_api.zip

@mstorsjo
Copy link
Contributor

Thanks - I've reproduced the issue and given it an initial look.

It's possible to reproduce this issue with something as simple as this:

$ cat test.def
LIBRARY foo.dll
EXPORTS
MyFunc
$ llvm-dlltool -m i386:x86-64 -d test.def -l test.lib
$  lld-link -wholearchive:test.lib
lld-link: error: test.lib(foo.dll): .idata$4 should not refer to special section 0

The reason for this, is that import libraries are usually treated somewhat specially. MSVC style import libraries ("short import library") have a couple regular object files, and a number of synthetic files that just tells the linker about what should exist in the DLL. (This contrary to the old style import libraries, "long import library", which GNU tools produce, where all object files are regular object files, which together build the import tables.)

Normally, when linking MSVC style import libraries, LLD doesn't really look at the files that are regular object file, and instead completely synthesize these tables instead. Now when linking with -wholearchive:, it forces the linker to actually process these object files which it usually ignores, and we hit this error.

So lesson 1: Don't force including import libraries with --whole-archive.

However, if generating a similar import library with MSVC tools instead, lib -def:test.def -out:msvc.lib, then the symbols look somewhat different, so LLD doesn't error out in the same way.

(I note that looking at the object files from that import library with obj2yaml triggers failed asserts, we should fix that.)

Even then, if I force linking the import library from MSVC with -wholearchive, it also misbehaves:

$ lld-link -wholearchive:msvc.lib -out:test.dll -subsystem:console -noentry -dll
lld-link: warning: ignoring section .debug$S with unrecognized magic 0x2
lld-link: warning: ignoring section .debug$S with unrecognized magic 0x2
lld-link: warning: ignoring section .debug$S with unrecognized magic 0x2
lld-link: error: section larger than 4 GiB: .data

So even if we fix the LLVM import library generation to output things in the same form as MSVC does, we practically can't link against them with -wholearchive with LLD. I guess that can be considered a limitation in LLD...

So, takeaways:

  • For Rust, can you avoid including import libraries in static libraries that you process with --whole-archive?
  • For LLVM, don't trigger failed asserts in obj2yaml on the object files from MSVC produced import libraries
  • For LLVM, maybe tweak import library generation to match what MSVC produces?
  • For LLD, should it detect this kind of import library object and ignore them, to make -wholearchive linking of import libraries actually work? Maybe not... With MSVC link.exe, doing the same kind of linking does succeed (contrary to LLD), but the output file is corrupt, so maybe this is not something that really is meant to be done. (This seems to happen with both MSVC and LLVM produced import libraries.)

@mati865
Copy link
Collaborator

mati865 commented Jun 19, 2024

Thank you so much for this. So the problem might lie within the librsvg build system because IIUC it's not Rust who added that --whole-archive.

Question to anyone who knows autotools better:
Is this --whole-archive added by libtool?

$ LANG=C make -j32 V=1
make  all-recursive
make[1]: Entering directory '/h/projects/librsvg'
Making all in .
make[2]: Entering directory '/h/projects/librsvg'
/bin/sh ./libtool  --tag=CC   --mode=link cc  -g -O2  -version-info 52:0:50 -export-dynamic -no-undefined -export-symbols-regex "^rsvg_.*" "-Wl,--gc-sections"    -o librsvg-2.la -rpath /clang64/lib   librsvg_c_api.la -lpng16 -lcairo-gobject -lfreetype -lgdk_pixbuf-2.0 -lgio-2.0 -lxml2 -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lharfbuzz -lcairo -lm  -lws2_32 -luserenv -lbcrypt -lntdll -v
libtool: link: rm -fr  .libs/librsvg-2.exp
libtool: link: /clang64/bin/nm -B   ./.libs/librsvg_c_api.a | /usr/bin/sed -n -e 's/^.*[         ]\([ABCDGIRSTW][ABCDGIRSTW]*\)[         ][      ]*\([_A-Za-z][_A-Za-z0-9]*\)\{0,1\}$/\1 \2 \2/p' | /usr/bin/sed '/ __gnu_lto/d' | /usr/bin/sed -e '/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //' | sort | uniq > .libs/librsvg-2.exp
libtool: link: /usr/bin/grep -E -e "^rsvg_.*" ".libs/librsvg-2.exp" > ".libs/librsvg-2.expT"
libtool: link: mv -f ".libs/librsvg-2.expT" ".libs/librsvg-2.exp"
libtool: link: if test DEF = "`/usr/bin/sed -n -e 's/^[  ]*//' -e '/^\(;.*\)*$/d' -e 's/^\(EXPORTS\|LIBRARY\)\([         ].*\)*$/DEF/p' -e q .libs/librsvg-2.exp`" ; then cp .libs/librsvg-2.exp .libs/librsvg-2-2.dll.def; else echo EXPORTS > .libs/librsvg-2-2.dll.def; cat .libs/librsvg-2.exp >> .libs/librsvg-2-2.dll.def; fi
libtool: link:  cc -shared .libs/librsvg-2-2.dll.def  -Wl,--whole-archive ./.libs/librsvg_c_api.a -Wl,--no-whole-archive  -lpng16 -lcairo-gobject -lfreetype -lgdk_pixbuf-2.0 -lgio-2.0 -lxml2 -lpangocairo-1.0 -lpango-1.0 -lgobject-2.0 -lglib-2.0 -lintl -lharfbuzz -lcairo -lws2_32 -luserenv -lbcrypt -lntdll  -g -O2 -Wl,--gc-sections   -o .libs/librsvg-2-2.dll -Wl,--enable-auto-image-base -Xlinker --out-implib -Xlinker .libs/librsvg-2.dll.a
ld.lld: error: librsvg_c_api.a(bcryptprimitives.dll): .idata$4 should not refer to special section 0
cc: error: linker command failed with exit code 1 (use -v to see invocation)
make[2]: *** [Makefile:900: librsvg-2.la] Error 1
make[2]: Leaving directory '/h/projects/librsvg'
make[1]: *** [Makefile:1158: all-recursive] Error 1
make[1]: Leaving directory '/h/projects/librsvg'
make: *** [Makefile:793: all] Error 2

Talking about this line: libtool: link: cc -shared .libs/librsvg-2-2.dll.def -Wl,--whole-archive ./.libs/librsvg_c_api.a ...., I have added -v to line 900, as you can see in the log above, but it's not the failing command.
Makefile.txt

@mstorsjo
Copy link
Contributor

As a side note here - it has to be mentioned, that this probably isn't an issue with the "long import library" format produced by the GNU tools - there, all object files are relevant and work entirely as usual object files, so linking them with --whole-archive should be fine.

So the problem might lie within the librsvg build system because IIUC it's not Rust who added that --whole-archive.

Question to anyone who knows autotools better: Is this --whole-archive added by libtool?

Not very familiar with this case, but it's quite plausible.

Using --whole-archive is generally quite common and reasonable with static libraries, so it might be hard to get around.

I'm not famliar with Rust's libraries though, but why does it end up with import library members in the same library as other implementation files? Overall, import libraries are special enough that it feels odd to merge them in like that. Or is that done to make linking work, without needing to separately specify which import libraries to link against, making those libraries implicitly enabled?

For the record, I tried tweaking obj2yaml to not fail on these files, and while it works, I'm not sure how useful it is, I'll consider if I want to upstream it or not. I also tried tweaking llvm-dlltool to change the details to match what MSVC produces - that works, but then linking fails with the same errors as when linking the MSVC produced import libraries. So not sure if this is worthwhile doing anyway...

@mati865
Copy link
Collaborator

mati865 commented Jun 20, 2024

I'm not famliar with Rust's libraries though, but why does it end up with import library members in the same library as other implementation files? Overall, import libraries are special enough that it feels odd to merge them in like that. Or is that done to make linking work, without needing to separately specify which import libraries to link against, making those libraries implicitly enabled?

I don't know the reasoning behind this, but when it comes to static libs, I suppose it's either by an accident or as an attempt to make things easier for the users. We've got the proof it makes things harder, so maybe it could be changed.

There are also .rlib files which are basically intermediate static libraries meant to be used only be the compiler, so they also contain metadata and IIRC some symbols not meant to exporting. The compiler will use them to create final outputs, so it needs to keep track of imported DLLs somehow. Probably combining import libraries with other objects was the easiest way to achieve that, but this is the compiler's own format, so I imagine it could be implemented in a different way.
Maybe we don't need to care about it, though? It has worked like that for quite some time now and didn't cause issues, so rlibs are surely linked without --whole-archive.

@revelator
Copy link
Contributor Author

damn seems i hit a hornets nest :) but im glad it got figured out.

@kleisauke
Copy link

Upstream Rust issue: rust-lang/rust#129020.

@kleisauke
Copy link

PR rust-lang/rust#129257 resolved this for MSVC. The windows-gnullvm targets are still affected.

AFAIK, there a currently 2 workarounds for this:

  1. Avoid linking with --whole-archive in librsvg, see for example 0002-avoid-link-whole.patch in librsvg: Update to 2.59.1 #21684.
  2. Avoid use of raw-dylib in Rust's standard library, see for example this patch.

@mstorsjo
Copy link
Contributor

After looking at rust-lang/rust#129257, I realized that there was one aspect I hadn't checked before. LLD with -wholearchive: on import libraries generated with LLVM fail. LLD with -wholearchive: on import libraries generated with MSVC fail slightly differently.

But MS link.exe with -wholearchive:, on import libraries from either LLVM or MSVC, does actually succeed. Doing that produces a binary that has a dependency on the DLL, but no symbols imported from it, which is somewhat unusual, but totally valid.

So with that in mind, I guess it could be reasonable to make LLD handle that case better than it does right now. Unfortunately, I think such a fix may turn out to be much more complicated than you'd expect it to, which is a bit annoying given how much of an odd corner case this is. But I think it could be reasonable to try to fix it in LLD after all.

For investigating and testing things, it would be interesting to have a sample of a rust generated short import library after rust-lang/rust#129257, where it has changed one section into a comdat section, if I understand it correctly; that'd be valuable to test against MS link.exe as well.

@ChrisDenton
Copy link

Here's an example lib you can download and use wholearchive on: https://github.com/ChrisDenton/processprng/actions/runs/11124768552. Note that Rust is not doing the comdat thing anymore. Instead it renames a single symbol.

Alternatively, you can just use wholearchive on an import lib generated by llvm or msvc and it should encounter the same problem.

@mstorsjo
Copy link
Contributor

mstorsjo commented Oct 1, 2024

Here's an example lib you can download and use wholearchive on: https://github.com/ChrisDenton/processprng/actions/runs/11124768552.

Thanks!

Note that Rust is not doing the comdat thing anymore. Instead it renames a single symbol.

Alternatively, you can just use wholearchive on an import lib generated by llvm or msvc and it should encounter the same problem.

Oh, ok, I see. (I was a bit confused by this, as the PR description in rust-lang/rust#129257 talked about renaming symbols, while the actual commits in the PR seemed to just set the comdat flag.)

Yeah I've tested wholearchive on import libs generated by LLVM and MSVC with lld before - but before I sit down and try to make it work, I wanted to have a sample of the comdat case that I thought you were generating. But if you've renamed the symbol, it should be less tricky for the linker to handle.

Anyway, thanks, I think I've got everything I need for being able to implement this, once I have time to sit down and work on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug reported-upstream Issues reported or fixed in upstream repository
Projects
None yet
Development

No branches or pull requests

6 participants