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

[LLD][COFF] start-lib / end-lib incorrectly discards symbols referenced in the same library #109707

Open
yuzhy8701 opened this issue Sep 23, 2024 · 1 comment
Labels

Comments

@yuzhy8701
Copy link

When linking in a library with start-lib and end-lib, lld-link would discard a symbol unless it is already seen in the prior objects. It discards the symbol even if the symbol is referenced in a latter object from the same library (latter as the command line order).

A simple case to repro (Powershell on Windows):

  1. Setup

    Set-Content -Path .\hello-time.h -Value @"
    #ifndef LIB_HELLO_TIME_H_
    #define LIB_HELLO_TIME_H_
    
    #include <string>
    
    std::string get_localtime();
    
    #endif
    "@
    
    Set-Content -Path .\hello-time.cc -Value @"
    #include "hello-time.h"
    #include <ctime>
    #include <string>
    
    std::string get_localtime() {
      std::time_t result = std::time(nullptr);
      return std::asctime(std::localtime(&result));
    }
    "@
    
    Set-Content -Path .\hello-greet.h -Value @"
    #ifndef MAIN_HELLO_GREET_H_
    #define MAIN_HELLO_GREET_H_
    
    #include <string>
    
    std::string get_greet(const std::string &thing);
    
    #endif
    "@
    
    Set-Content -Path .\hello-greet.cc -Value @"
    #include "hello-time.h"
    #include "hello-greet.h"
    #include <string>
    
    std::string get_greet(const std::string& who) {
      return "Hello " + who + "; " + get_localtime();
    }
    "@
    
    Set-Content -Path .\hello-world.cc -Value @"
    #include "hello-greet.h"
    #include <iostream>
    #include <string>
    
    int main(int argc, char** argv) {
      std::cout << get_greet("world") << std::endl;
      return 0;
    }
    "@
  2. The following succeeds:

    If (Test-Path 'out') {
        Remove-Item -Path 'out' -Recurse -Force -Verbose
    }
    New-Item -Path 'out' -ItemType Directory
    
    clang-cl.exe /c 'hello-time.cc' /Fo'out/hello-time.obj'
    clang-cl.exe /c 'hello-greet.cc' /Fo'out/hello-greet.obj'
    clang-cl.exe /c 'hello-world.cc' /Fo'out/hello-world.obj'
    
    lld-link.exe /OUT:'out/hello-world.exe' `
        out/hello-world.obj `
        '/start-lib' `
        out/hello-greet.obj `
        out/hello-time.obj `
        '/end-lib'
  3. The following fails with error: lld-link: error: relocation against symbol in discarded section: ?get_localtime@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ

    $ErrorActionPreference = "Stop"
    
    If (Test-Path 'out') {
        Remove-Item -Path 'out' -Recurse -Force -Verbose
    }
    New-Item -Path 'out' -ItemType Directory
    
    clang-cl.exe /c 'hello-time.cc' /Fo'out/hello-time.obj'
    clang-cl.exe /c 'hello-greet.cc' /Fo'out/hello-greet.obj'
    clang-cl.exe /c 'hello-world.cc' /Fo'out/hello-world.obj'
    
    lld-link.exe /OUT:'out/hello-world.exe' `
        out/hello-world.obj `
        '/start-lib' `
        out/hello-time.obj `
        out/hello-greet.obj `
        '/end-lib'

Note that the only difference between success and fail cases is the object order between start-lib and end-lib. I'm able to reproduce with the latest llvm version (19.1.0).

@llvmbot
Copy link
Collaborator

llvmbot commented Sep 23, 2024

@llvm/issue-subscribers-lld-coff

Author: None (yuzhy8701)

When linking in a library with `start-lib` and `end-lib`, `lld-link` would discard a symbol unless it is already seen in the prior objects. It discards the symbol even if the symbol is referenced in a latter object from the same library (latter as the command line order).

A simple case to repro (Powershell on Windows):

  1. Setup

    Set-Content -Path .\hello-time.h -Value @"
    #ifndef LIB_HELLO_TIME_H_
    #define LIB_HELLO_TIME_H_
    
    #include &lt;string&gt;
    
    std::string get_localtime();
    
    #endif
    "@
    
    Set-Content -Path .\hello-time.cc -Value @"
    #include "hello-time.h"
    #include &lt;ctime&gt;
    #include &lt;string&gt;
    
    std::string get_localtime() {
      std::time_t result = std::time(nullptr);
      return std::asctime(std::localtime(&amp;result));
    }
    "@
    
    Set-Content -Path .\hello-greet.h -Value @"
    #ifndef MAIN_HELLO_GREET_H_
    #define MAIN_HELLO_GREET_H_
    
    #include &lt;string&gt;
    
    std::string get_greet(const std::string &amp;thing);
    
    #endif
    "@
    
    Set-Content -Path .\hello-greet.cc -Value @"
    #include "hello-time.h"
    #include "hello-greet.h"
    #include &lt;string&gt;
    
    std::string get_greet(const std::string&amp; who) {
      return "Hello " + who + "; " + get_localtime();
    }
    "@
    
    Set-Content -Path .\hello-world.cc -Value @"
    #include "hello-greet.h"
    #include &lt;iostream&gt;
    #include &lt;string&gt;
    
    int main(int argc, char** argv) {
      std::cout &lt;&lt; get_greet("world") &lt;&lt; std::endl;
      return 0;
    }
    "@
  2. The following succeeds:

    If (Test-Path 'out') {
        Remove-Item -Path 'out' -Recurse -Force -Verbose
    }
    New-Item -Path 'out' -ItemType Directory
    
    clang-cl.exe /c 'hello-time.cc' /Fo'out/hello-time.obj'
    clang-cl.exe /c 'hello-greet.cc' /Fo'out/hello-greet.obj'
    clang-cl.exe /c 'hello-world.cc' /Fo'out/hello-world.obj'
    
    lld-link.exe /OUT:'out/hello-world.exe' `
        out/hello-world.obj `
        '/start-lib' `
        out/hello-greet.obj `
        out/hello-time.obj `
        '/end-lib'
  3. The following fails with error: lld-link: error: relocation against symbol in discarded section: ?get_localtime@@<!-- -->YA?AV?$basic_string@<!-- -->DU?$char_traits@<!-- -->D@<!-- -->std@@<!-- -->V?$allocator@<!-- -->D@<!-- -->2@@<!-- -->std@@<!-- -->XZ

    $ErrorActionPreference = "Stop"
    
    If (Test-Path 'out') {
        Remove-Item -Path 'out' -Recurse -Force -Verbose
    }
    New-Item -Path 'out' -ItemType Directory
    
    clang-cl.exe /c 'hello-time.cc' /Fo'out/hello-time.obj'
    clang-cl.exe /c 'hello-greet.cc' /Fo'out/hello-greet.obj'
    clang-cl.exe /c 'hello-world.cc' /Fo'out/hello-world.obj'
    
    lld-link.exe /OUT:'out/hello-world.exe' `
        out/hello-world.obj `
        '/start-lib' `
        out/hello-time.obj `
        out/hello-greet.obj `
        '/end-lib'

Note that the only difference between success and fail cases is the object order between start-lib and end-lib. I'm able to reproduce with the latest llvm version (19.1.0).

jrguzman-ms pushed a commit to msft-mirror-aosp/platform.build.bazel that referenced this issue Oct 3, 2024
This change enables thin LTO. This usually gives LTO results similar
to full LTO while being faster for big binaries.

On linux we implement distributed thin LTO. On macos we use the default
multi-threaded thin LTO. Bazel currently doesn't work with LTO on
windows due to llvm/llvm-project#109707 and
bazelbuild/bazel#23742.

Change-Id: Icdb6442f06fc2b841ac409a8cd6e113f0240cac2
jrguzman-ms pushed a commit to msft-mirror-aosp/platform.build.bazel that referenced this issue Oct 10, 2024
This change enables thin LTO. This usually gives LTO results similar
to full LTO while being faster for big binaries.

On linux we implement distributed thin LTO. On macos we use the default
multi-threaded thin LTO. Bazel currently doesn't work with LTO on
windows due to llvm/llvm-project#109707 and
bazelbuild/bazel#23742.

(cherry picked from commit 3529260)
Change-Id: I68a1480d5c6835eaf0c7f92f4c9b8ff44a25903a
Merged-In: Icdb6442f06fc2b841ac409a8cd6e113f0240cac2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants