]> git.alrj.org Git - bold.git/blobdiff - Bold/linker.py
First support for .gnu.hash/DT_GNU_HASH.
[bold.git] / Bold / linker.py
index 505e2f130f3f3c1a7863a08d36a301119ad250d9..935b462f5d50c8c5bfefebe7c8b6e06adf7937a4 100644 (file)
@@ -18,6 +18,7 @@ from BinArray import BinArray
 from elf import Elf64, Elf64_Phdr, Elf64_Shdr, TextSegment, DataSegment
 from elf import SStrtab, SSymtab, SProgBits, SNobits, Dynamic, Interpreter
 from errors import *
+from ctypes import CDLL
 from ctypes.util import find_library
 import struct
 
@@ -47,6 +48,7 @@ class BoldLinker(object):
     self.output = Elf64()
     self.global_symbols = {}
     self.undefined_symbols = set()
+    self.common_symbols = set()
 
 
   def add_object(self, filename):
@@ -63,9 +65,10 @@ class BoldLinker(object):
     """Find out the globally available symbols, as well as the globally
     undefined ones (which should be found in external libraries."""
 
-    # Gather the "extern" symbols from each input files.
+    # Gather the "extern" and common symbols from each input files.
     for i in self.objs:
       self.undefined_symbols.update(i.undefined_symbols)
+      self.common_symbols.update(i.common_symbols)
 
     # Make a dict with all the symbols declared globally.
     # Key is the symbol name, value will later be set to the final
@@ -84,6 +87,14 @@ class BoldLinker(object):
     # Find out which symbols aren't really defined anywhere
     self.undefined_symbols.difference_update(self.global_symbols)
 
+    # A symbol declared as COMMON in one object may very well have been
+    # defined in another. In this case, it will be present in the
+    # global_symbols.
+    # Take a copy because we can't change the set's size inside the loop
+    for i in self.common_symbols.copy():
+      if i[0] in self.global_symbols:
+        self.common_symbols.remove(i)
+
 
   def build_external(self, with_jump=False, align_jump=False):
     """
@@ -97,9 +108,12 @@ class BoldLinker(object):
     symbols = sorted(list(self.undefined_symbols))
 
     # Those three will soon be known...
-    symbols.remove('_bold__functions_count')
-    symbols.remove('_bold__functions_hash')
-    symbols.remove('_bold__functions_pointers')
+    if '_bold__functions_count' in symbols:
+      symbols.remove('_bold__functions_count')
+    if '_bold__functions_hash' in symbols:
+      symbols.remove('_bold__functions_hash')
+    if '_bold__functions_pointers' in symbols:
+      symbols.remove('_bold__functions_pointers')
 
     # Create the fake ELF object.
     fo = Elf64() # Don't care about most parts of ELF header (?)
@@ -118,7 +132,6 @@ class BoldLinker(object):
     bss_shdr = Elf64_Shdr()
     bss_shdr.sh_type = SHT_NOBITS
     bss_shdr.sh_flags = (SHF_WRITE | SHF_ALLOC)
-    bss_shdr.sh_size = len(symbols) * 8
     bss_shdr.content = BinArray("")
     fo.shdrs.append(bss_shdr)
     fo.sections['.bss'] = bss_shdr
@@ -145,6 +158,16 @@ class BoldLinker(object):
     fo.global_symbols['_bold__functions_hash'] = (data_shdr, 0)
     fo.global_symbols['_bold__functions_pointers'] = (bss_shdr, 0)
 
+    # The COMMON symbols. Assign an offset in .bss, declare as global.
+    bss_common_offset = len(symbols) * 8
+    for s_name, s_size, s_alignment in self.common_symbols:
+      padding = (s_alignment - (bss_common_offset % s_alignment)) % s_alignment
+      bss_common_offset += padding
+      fo.global_symbols[s_name] = (bss_shdr, bss_common_offset)
+      bss_common_offset += s_size
+
+    bss_shdr.sh_size = bss_common_offset
+
     for n, i in enumerate(symbols):
       # The hash is always in .data
       h = "_bold__hash_%s" % i
@@ -199,6 +222,26 @@ class BoldLinker(object):
     self.shlibs.append(fullname)
 
 
+  def check_external(self):
+    """Verify that all globally undefined symbols are present in shared
+    libraries."""
+    libs = []
+    for libname in self.shlibs:
+      libs.append(CDLL(libname))
+
+    for symbol in self.undefined_symbols:
+      # Hackish ! Eek!
+      if symbol.startswith('_bold__'):
+        continue
+      found = False
+      for lib in libs:
+        if hasattr(lib, symbol):
+          found = True
+          break
+      if not found:
+        raise UndefinedSymbol(symbol)
+
+
   def link(self):
     """Do the actual linking."""
     # Prepare two segments. One for .text, the other for .data + .bss