[PATCH] D25014: [ELF] Change the way we compute file offsets

Eugene Leviant via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 28 04:00:34 PDT 2016


evgeny777 created this revision.
evgeny777 added reviewers: rafael, ruiu.
evgeny777 added subscribers: grimar, ikudrin, llvm-commits.
evgeny777 set the repository for this revision to rL LLVM.
evgeny777 added a project: lld.

Imagine we have too sections .foo and .bar with virtual addresses 0x10000 and 0x20000, which share the same segment:

```
PHDRS { all PT_LOAD; }
SECTIONS {
   .foo (0x10000) : { *(.foo*) } : all
   .bar (0x20000) : { *(.bar*) } : all
}
```
Now also imagine that section .foo is the first section in PT_LOAD and segment virtual address is the same as section .foo, i.e 0x10000
As we have only one PT_LOAD, OS kernel should allocate the both sections correctly using only one memory mapping operation. The only
way this can be done is setting difference between file offsets of .bar and .foo to the same value as difference between their virtual addresses, i.e:

File_offset(.bar) - File_offset(.foo) = VA(.bar) - VA(.foo) = 0x10000

In such case both sections be correctly loaded using a single mmap() call.

Also It looks like both gold and ld use the same approach.

Repository:
  rL LLVM

https://reviews.llvm.org/D25014

Files:
  ELF/OutputSections.h
  ELF/Writer.cpp
  test/ELF/linkerscript/outsections-addr.s

Index: test/ELF/linkerscript/outsections-addr.s
===================================================================
--- test/ELF/linkerscript/outsections-addr.s
+++ test/ELF/linkerscript/outsections-addr.s
@@ -81,7 +81,7 @@
 #CHECK:      SHF_ALLOC
 #CHECK:    ]
 #CHECK:    Address: 0x4008
-#CHECK:    Offset: 0x2008
+#CHECK:    Offset: 0x3008
 #CHECK:    Size: 8
 #CHECK:    Link: 0
 #CHECK:    Info: 0
@@ -96,7 +96,7 @@
 #CHECK:      SHF_ALLOC
 #CHECK:    ]
 #CHECK:    Address: 0x5010
-#CHECK:    Offset: 0x2010
+#CHECK:    Offset: 0x4010
 #CHECK:    Size: 8
 #CHECK:    Link: 0
 #CHECK:    Info: 0
Index: ELF/Writer.cpp
===================================================================
--- ELF/Writer.cpp
+++ ELF/Writer.cpp
@@ -541,6 +541,8 @@
   if (!First)
     First = Sec;
   H.p_align = std::max<typename ELFT::uint>(H.p_align, Sec->getAlignment());
+  if (H.p_type == PT_LOAD && !Config->OFormatBinary)
+    Sec->FirstInPtLoad = First;
 }
 
 template <class ELFT>
@@ -1050,7 +1052,7 @@
   Phdr Note(PT_NOTE, PF_R);
   for (OutputSectionBase<ELFT> *Sec : OutputSections) {
     if (!(Sec->getFlags() & SHF_ALLOC))
-      break;
+      continue;
 
     // If we meet TLS section then we create TLS header
     // and put all TLS sections inside for further use when
@@ -1189,7 +1191,18 @@
   // and does not need any other offset adjusting.
   if (Config->Relocatable || !(Sec->getFlags() & SHF_ALLOC))
     return Off;
-  return alignTo(Off, Target->MaxPageSize, Sec->getVA());
+
+  OutputSectionBase<ELFT> *First = Sec->FirstInPtLoad;
+  // If two sections share the same PT_LOAD the file offset is calculated using
+  // this formula: Off2 = Off1 + (VA2 - VA1).
+  // lld does not sort sections by VA, so next section VA may be less than
+  // previous section VA than previous one. If we return smaller offset we'll 
+  // crash in writeTo(), due to writing outside of buffer boundary, so we 
+  // calculate maximum offset to avoid this situation.
+  return !First || Sec == First
+             ? alignTo(Off, Target->MaxPageSize, Sec->getVA())
+             : std::max(Off,
+                        First->getFileOffset() + Sec->getVA() - First->getVA());
 }
 
 template <class ELFT, class uintX_t>
@@ -1209,6 +1222,7 @@
   for (OutputSectionBase<ELFT> *Sec : OutputSections)
     if (Sec->getFlags() & SHF_ALLOC)
       setOffset(Sec, Off);
+
   FileSize = alignTo(Off, sizeof(uintX_t));
 }
 
Index: ELF/OutputSections.h
===================================================================
--- ELF/OutputSections.h
+++ ELF/OutputSections.h
@@ -77,6 +77,7 @@
   void setVA(uintX_t VA) { Header.sh_addr = VA; }
   uintX_t getVA() const { return Header.sh_addr; }
   void setFileOffset(uintX_t Off) { Header.sh_offset = Off; }
+  uintX_t getFileOffset() { return Header.sh_offset; }
   void setSHName(unsigned Val) { Header.sh_name = Val; }
   void writeHeaderTo(Elf_Shdr *SHdr);
   StringRef getName() { return Name; }
@@ -108,6 +109,8 @@
   // Typically the first section of each PT_LOAD segment has this flag.
   bool PageAlign = false;
 
+  OutputSectionBase<ELFT> *FirstInPtLoad = nullptr;
+
   virtual void finalize() {}
   virtual void finalizePieces() {}
   virtual void assignOffsets() {}


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D25014.72792.patch
Type: text/x-patch
Size: 3211 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20160928/59f8c7f6/attachment.bin>


More information about the llvm-commits mailing list