]> git.alrj.org Git - bold.git/blobdiff - Bold/linker.py
Check for external symbols.
[bold.git] / Bold / linker.py
index 505e2f130f3f3c1a7863a08d36a301119ad250d9..625a28d995de623e54e1c14435b004443e7d59fc 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 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
 
 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.output = Elf64()
     self.global_symbols = {}
     self.undefined_symbols = set()
+    self.common_symbols = set()
 
 
   def add_object(self, filename):
 
 
   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."""
 
     """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)
     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
 
     # 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)
 
     # 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):
     """
 
   def build_external(self, with_jump=False, align_jump=False):
     """
@@ -115,10 +126,17 @@ class BoldLinker(object):
     fo.shdrs.append(data_shdr)
     fo.sections['.data'] = data_shdr
 
     fo.shdrs.append(data_shdr)
     fo.sections['.data'] = data_shdr
 
+    # .bss will contain pointers to resolved external functions, as well as
+    # the COMMON symbols (from C tentative declaration).
+    bss_size = len(symbols) * 8
+    for s_name, s_size, s_alignment in self.common_symbols:
+      padding = (s_alignment - (bss_size % s_alignment))
+      bss_size += padding + s_size
+
     bss_shdr = Elf64_Shdr()
     bss_shdr.sh_type = SHT_NOBITS
     bss_shdr.sh_flags = (SHF_WRITE | SHF_ALLOC)
     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.sh_size = bss_size
     bss_shdr.content = BinArray("")
     fo.shdrs.append(bss_shdr)
     fo.sections['.bss'] = bss_shdr
     bss_shdr.content = BinArray("")
     fo.shdrs.append(bss_shdr)
     fo.sections['.bss'] = bss_shdr
@@ -145,6 +163,15 @@ class BoldLinker(object):
     fo.global_symbols['_bold__functions_hash'] = (data_shdr, 0)
     fo.global_symbols['_bold__functions_pointers'] = (bss_shdr, 0)
 
     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))
+      bss_common_offset += padding
+      fo.global_symbols[s_name] = (bss_shdr, bss_common_offset)
+      bss_common_offset += s_size
+
+
     for n, i in enumerate(symbols):
       # The hash is always in .data
       h = "_bold__hash_%s" % i
     for n, i in enumerate(symbols):
       # The hash is always in .data
       h = "_bold__hash_%s" % i
@@ -199,6 +226,26 @@ class BoldLinker(object):
     self.shlibs.append(fullname)
 
 
     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
   def link(self):
     """Do the actual linking."""
     # Prepare two segments. One for .text, the other for .data + .bss