Skip to content

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

Closed
@yuzhy8701

Description

@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 <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).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions