llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.11k stars 12.01k forks source link

lld incorrectly emits region overflow errors when linker relaxation would prevent an overflow #62423

Open korran opened 1 year ago

korran commented 1 year ago

I've written an LLD test-case that fails at top-of-tree:

# REQUIRES: riscv                                                                                           

# RUN: rm -rf %t && split-file %s %t && cd %t                                                               

## Check that relaxation prevents region overflow                                                           

# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c,+relax a.s -o a.32c.o                                
# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+c,+relax b.s -o b.32c.o                                
# RUN: ld.lld -T lds a.32c.o b.32c.o -o 32c                                                                 
# RUN: llvm-objdump --section-headers 32c | FileCheck %s --check-prefixes=RELAX_SECTIONS                    
# RELAX_SECTIONS:   1 .text         0000000a 00000000 TEXT                                                  

## Check that we still overflow with relaxation disabled                                                    

# RUN: not ld.lld -T lds a.32c.o b.32c.o --no-relax -o /dev/null 2>&1 | FileCheck --check-prefix=ERR0 %s    
# ERR0: ld.lld: error: section '.text' will not fit in region 'ROM'                                         

#--- a.s                                                                                                    
.global _start                                                                                              
_start:                                                                                                     
  # These calls can be relaxed to be much smaller, enough to fit within the                                 
  # tiny ROM region                                                                                         
  call bar                                                                                                  
  call bar                                                                                                  
  call bar                                                                                                  
  call bar                                                                                                  

#--- b.s                                                                                                    
.global bar                                                                                                  
bar:                                                                                                        
  ret                                                                                                       

#--- lds                                                                                                    
MEMORY {                                                                                                    
  ROM (rx) : ORIGIN = 0, LENGTH = 12                                                                        
}                                                                                                           
SECTIONS {                                                                                                  
  .text 0x00000 : { *(.text) } > ROM                                                                        
}

Because of this bug, the call to ld.ldd on line 9 will fail with this error:

ld.lld: error: section '.text' will not fit in region 'ROM': overflowed by 22 bytes

If I increase the length of the ROM region, it succeeds, and the .text section in the output file is only 10 bytes; less than the original region size.

$ tail lds
MEMORY {                                                                                                    
  ROM (rx) : ORIGIN = 0, LENGTH = 40                                                                        
}
$ llvm-objdump --section-headers 32c 
Sections:                                                                                                                                                                                                     
Idx Name          Size     VMA      Type                                                                                                                                                                    
  0               00000000 00000000                                                                                                                                                                             
  1 .text         0000000a 00000000 TEXT                                                                                                                                                                
<snip>

I believe the first call to LinkerScript::assignAddresses() is the one that triggers the error, and it occurs before any relaxation passes have been done. Later passes that happen after relaxation don't trigger any errors, but it's too late.

korran commented 1 year ago

My attempt to fix this issue (with test): https://reviews.llvm.org/D149432

llvmbot commented 1 year ago

@llvm/issue-subscribers-lld-elf

kupiakos commented 6 months ago

@korran It looks like LLVM has moved to using Github PRs for review. Do you want me to rebase your fix and send in a PR, or would you like to? My team is lucky to have not hit this issue yet but this could block uprev for us.