]> git.alrj.org Git - bold.git/blobdiff - Bold/linker.py
Check for external symbols.
[bold.git] / Bold / linker.py
index 8bc170a293c2f0b944ae3527232094399b13242c..625a28d995de623e54e1c14435b004443e7d59fc 100644 (file)
@@ -1,4 +1,3 @@
-#! /usr/bin/python
 # -*- coding: utf-8 -*-
 # kate: space-indent on; indent-width 2; mixedindent off; indent-mode python;
 
@@ -7,8 +6,8 @@
 # This file is part of bold, the Byte Optimized Linker.
 #
 # You can redistribute this file and/or modify it under the terms of the
-# GNU Lesser General Public License as published by the Free Software
-# Foundation, version 2.1.
+# GNU General Public License as published by the Free Software Foundation,
+# either version 3 of the License or (at your option) any later version.
 
 """
 Main entry point for the bold linker.
@@ -19,25 +18,25 @@ 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
 
+
 def hash_name(name):
-  """Caculate the hash of the function name."""
+  """Caculate the hash of the function name.
+  @param name: the string to hash
+  @return: 32 bits hash value.
+  """
   h = 0
   for c in name:
-    h = (ord(c) - h + (h << 6) + (h << 16) & 0xffffffff)
+    h = ((h * 0x21) ^ ord(c)) & 0xffffffff
   return h
 
+
 class BoldLinker(object):
   """A Linker object takes one or more objects files, optional shared libs,
   and arranges all this in an executable.
-
-  Important note: the external functions from the libraries are NOT resolved.
-  This import is left to the user, as it can be done more efficiently by hash.
-  (http://www.linuxdemos.org/contentarticle/how_to_start_4k_introdev_with_ibh)
-  For this, a very useful symbol is exported, : _dt_debug, the address of the
-  DT_DEBUG's d_ptr.
   """
 
   def __init__(self):
@@ -49,21 +48,27 @@ class BoldLinker(object):
     self.output = Elf64()
     self.global_symbols = {}
     self.undefined_symbols = set()
+    self.common_symbols = set()
+
 
   def add_object(self, filename):
-    """Add a relocatable file as input."""
+    """Add a relocatable file as input.
+    @param filename: path to relocatable object file to add
+    """
     obj = Elf64(filename)
     obj.resolve_names()
     obj.find_symbols()
     self.objs.append(obj)
 
+
   def build_symbols_tables(self):
     """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
@@ -82,10 +87,20 @@ 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=True):
+  def build_external(self, with_jump=False, align_jump=False):
     """
     Generate a fake relocatable object, for dynamic linking.
+    This object is then automatically added in the list of ebjects to link.
+    TODO: This part is extremely non-portable.
     """
 
     # Find out all the undefined symbols. They're the one we'll need to resolve
@@ -111,10 +126,17 @@ class BoldLinker(object):
     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.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
@@ -141,6 +163,15 @@ 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))
+      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
@@ -163,7 +194,6 @@ class BoldLinker(object):
       class dummy: pass
       rela_shdr = Elf64_Shdr()
       rela_shdr.sh_type = SHT_RELA
-      # rela_shdr.sh_info = fo.shdrs.index(text_shdr)
       rela_shdr.target = text_shdr
       rela_shdr.sh_flags = 0
       rela_shdr._content = dummy() # We only need a container for relatab...
@@ -179,7 +209,6 @@ class BoldLinker(object):
         reloc.symbol = dummy()
         reloc.symbol.st_shndx = SHN_UNDEF
         reloc.symbol.name = "_bold__%s" % i
-        # reloc.symbol.st_value = 0
         relatab.append(reloc)
       fo.shdrs.append(rela_shdr)
       fo.sections['.rela.text'] = rela_shdr
@@ -196,6 +225,27 @@ class BoldLinker(object):
       raise LibNotFound(libname)
     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
@@ -304,13 +354,6 @@ class BoldLinker(object):
     self.global_symbols["_dt_debug"] = dynamic.dt_debug_address
     self.global_symbols["_DYNAMIC"] = dynamic.virt_addr
 
-    # For now, it's an error. Later, we could try to find them in the shared
-    # libraries.
-    #if len(self.undefined_symbols):
-    #  raise UndefinedSymbol(self.undefined_symbols.pop())
-
-
-
     # We can now do the actual relocation
     for i in self.objs:
       i.apply_relocation(self.global_symbols)
@@ -326,6 +369,7 @@ class BoldLinker(object):
   def toBinArray(self):
     return self.output.toBinArray()
 
+
   def tofile(self, file_object):
     return self.output.toBinArray().tofile(file_object)