Index: llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp =================================================================== --- llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp +++ llvm/lib/Target/AVR/MCTargetDesc/AVRELFObjectWriter.cpp @@ -69,8 +69,13 @@ switch (Modifier) { default: llvm_unreachable("Unsupported Modifier"); - case MCSymbolRefExpr::VK_None: + case MCSymbolRefExpr::VK_None: { + auto &symbol = cast(Target.getSymA()->getSymbol()); + if (symbol.getType() == ELF::STT_NOTYPE) + // Not a global variable, so probably a function pointer. + return ELF::R_AVR_16_PM; return ELF::R_AVR_16; + } case MCSymbolRefExpr::VK_AVR_NONE: return ELF::R_AVR_16_PM; case MCSymbolRefExpr::VK_AVR_DIFF16: Index: llvm/test/CodeGen/AVR/global-relocs.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AVR/global-relocs.ll @@ -0,0 +1,42 @@ +; RUN: llc < %s -march=avr -filetype=obj | llvm-objdump -Dr - | FileCheck %s + +; This test checks whether the correct relocation type (R_AVR_16 or +; R_AVR_16_PM) is used for relocations in global variables (such as function +; and global variable pointers). Function pointers need a special relocation +; type so that the linker will use an address in program words (a pointer to +; program space shifted left by one). + +target datalayout = "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8" +target triple = "avr" + +; Some globals to refer to. +@someGlobal = dso_local constant i32 5, align 2 +@someProgmemGlobal = dso_local addrspace(1) constant i16 5, align 2 + +; Reduced testcase from Rust. +@MY_VTABLE = internal constant <{ i8 addrspace(1)* }> <{ i8 addrspace(1)* bitcast (void () addrspace(1)* @wake to i8 addrspace(1)*) }>, align 1 +; CHECK-LABEL: : +; CHECK: R_AVR_16_PM wake + +@ptrToFunction = dso_local constant i8 addrspace(1)* bitcast (void () addrspace(1)* @wake to i8 addrspace(1)*), align 1 +; CHECK-LABEL: : +; CHECK: R_AVR_16_PM wake + +@ptrToGlobal = dso_local constant i32* @someGlobal, align 1 +; CHECK-LABEL: : +; CHECK: R_AVR_16 someGlobal + +@ptrToProgmemGlobal = dso_local constant i16 addrspace(1)* @someProgmemGlobal, align 1 +; CHECK-LABEL: : +; CHECK: R_AVR_16 someProgmemGlobal + +@ptrToProgmemGlobal2 = dso_local constant i8 addrspace(1)* bitcast (i16 addrspace(1)* @someProgmemGlobal to i8 addrspace(1)*), align 1 +; CHECK-LABEL: : +; CHECK: R_AVR_16 someProgmemGlobal + +@ptrToFunction2 = dso_local global void () addrspace(1)* @wake, align 1 +; CHECK-LABEL: : +; CHECK: R_AVR_16_PM wake + +; A function to refer to. +declare dso_local void @wake() addrspace(1)