From 96659df09c7b6920651dcbda8f11caad95d9bde8 Mon Sep 17 00:00:00 2001 From: George Rimar Date: Tue, 30 Aug 2016 09:54:01 +0000 Subject: [PATCH] [ELF] - Linkerscript: implemented ADDR command. ADDR(section) Return the absolute address (the VMA) of the named section. Used in the wild, eg.: https://searchcode.com/file/53617342/arch/x86/kernel/vmlinux.lds.S Differential revision: https://reviews.llvm.org/D23913 llvm-svn: 280070 --- lld/ELF/LinkerScript.cpp | 31 ++++++++++++++++++ lld/ELF/LinkerScript.h | 1 + lld/test/ELF/linkerscript/linkerscript-addr.s | 32 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 lld/test/ELF/linkerscript/linkerscript-addr.s diff --git a/lld/ELF/LinkerScript.cpp b/lld/ELF/LinkerScript.cpp index 16c3aef9e3db..cd67d189c4a0 100644 --- a/lld/ELF/LinkerScript.cpp +++ b/lld/ELF/LinkerScript.cpp @@ -532,6 +532,16 @@ template bool LinkerScript::hasPhdrsCommands() { return !Opt.PhdrsCommands.empty(); } +template +typename ELFT::uint +LinkerScript::getOutputSectionAddress(StringRef Name) { + for (OutputSectionBase *Sec : *OutputSections) + if (Sec->getName() == Name) + return Sec->getVA(); + error("undefined section " + Name); + return 0; +} + template typename ELFT::uint LinkerScript::getOutputSectionSize(StringRef Name) { for (OutputSectionBase *Sec : *OutputSections) @@ -1044,6 +1054,21 @@ static uint64_t getSectionSize(StringRef Name) { } } +static uint64_t getSectionAddress(StringRef Name) { + switch (Config->EKind) { + case ELF32LEKind: + return Script::X->getOutputSectionAddress(Name); + case ELF32BEKind: + return Script::X->getOutputSectionAddress(Name); + case ELF64LEKind: + return Script::X->getOutputSectionAddress(Name); + case ELF64BEKind: + return Script::X->getOutputSectionAddress(Name); + default: + llvm_unreachable("unsupported target"); + } +} + static uint64_t getHeaderSize() { switch (Config->EKind) { case ELF32LEKind: @@ -1154,6 +1179,12 @@ Expr ScriptParser::readPrimary() { // Built-in functions are parsed here. // https://sourceware.org/binutils/docs/ld/Builtin-Functions.html. + if (Tok == "ADDR") { + expect("("); + StringRef Name = next(); + expect(")"); + return [=](uint64_t Dot) { return getSectionAddress(Name); }; + } if (Tok == "ASSERT") return readAssert(); if (Tok == "ALIGN") { diff --git a/lld/ELF/LinkerScript.h b/lld/ELF/LinkerScript.h index d93023fbe6d9..e207e4087ecc 100644 --- a/lld/ELF/LinkerScript.h +++ b/lld/ELF/LinkerScript.h @@ -151,6 +151,7 @@ public: void assignAddresses(); int compareSections(StringRef A, StringRef B); bool hasPhdrsCommands(); + uintX_t getOutputSectionAddress(StringRef Name); uintX_t getOutputSectionSize(StringRef Name); uintX_t getHeaderSize(); diff --git a/lld/test/ELF/linkerscript/linkerscript-addr.s b/lld/test/ELF/linkerscript/linkerscript-addr.s new file mode 100644 index 000000000000..2d3a7ab35767 --- /dev/null +++ b/lld/test/ELF/linkerscript/linkerscript-addr.s @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: . = 0x1000; \ +# RUN: .text : { *(.text*) } \ +# RUN: .foo.1 : { *(.foo.1) } \ +# RUN: .foo.2 ADDR(.foo.1) + 0x100 : { *(.foo.2) } \ +# RUN: .foo.3 : { *(.foo.3) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t1 +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000000 0000000000001000 TEXT DATA +# CHECK-NEXT: 2 .foo.1 00000008 0000000000001000 DATA +# CHECK-NEXT: 3 .foo.2 00000008 0000000000001100 DATA +# CHECK-NEXT: 4 .foo.3 00000008 0000000000001108 DATA + +.text +.globl _start +_start: + +.section .foo.1,"a" + .quad 1 + +.section .foo.2,"a" + .quad 2 + +.section .foo.3,"a" + .quad 3