]> git.alrj.org Git - bold.git/blob - elf/elf.py
First working version.
[bold.git] / elf / elf.py
1 # -*- coding: utf-8 -*-
2
3 # kate: space-indent on; indent-width 2; mixedindent off; indent-mode python;
4
5 # Copyright (C) 2009 Amand 'alrj' Tihon <amand.tihon@alrj.org>
6 #
7 # This file is part of bold, the Byte Optimized Linker.
8 # Heavily inspired by elf.h from the GNU C Library.
9 #
10 # You can redistribute this file and/or modify it under the terms of the
11 # GNU Lesser General Public License as published by the Free Software
12 # Foundation, version 2.1.
13
14
15 from BinArray import BinArray
16 from constants import *
17 import struct
18
19 # Helpful decorator
20 def nested_property(c):
21   return property(**c())
22
23 #--------------------------------------------------------------------------
24 #  Elf
25 #--------------------------------------------------------------------------
26
27 class Elf64(object):
28   """Handles an Elf64 object."""
29   interpreter = "/lib64/ld-linux-x86-64.so.2"
30
31   def __init__(self, path=None):
32     object.__init__(self)
33     self.header = Elf64_Ehdr()
34     self.header.owner = self
35     self.shdrs = []
36     self.phdrs = []
37     self.shlibs = []
38     self.sections = {}
39     self.segments = []
40     self.local_symbols = {}
41     self.global_symbols = {}
42     self.undefined_symbols = []
43
44     if path:
45       self.fromfile(path)
46
47   def fromfile(self, path):
48     f = file(path, "rb")
49
50     # Load Elf header
51     data = BinArray()
52     data.fromfile(f, Elf64_Ehdr.size)
53     self.header.fromBinArray(data)
54
55     # Load sections headers
56     f.seek(self.header.e_shoff)
57     for i in range(self.header.e_shnum):
58       data = BinArray()
59       data.fromfile(f, self.header.e_shentsize)
60       h = Elf64_Shdr(i, data)
61       h.owner = self
62       self.shdrs.append(h)
63
64     # Read sections content
65     for sh in self.shdrs:
66       data = BinArray()
67       if sh.sh_type != SHT_NOBITS:
68         f.seek(sh.sh_offset)
69         data.fromfile(f, sh.sh_size)
70       sh.content = data
71
72     f.close()
73
74   def resolve_names(self):
75     # The .shstrtab index is in Elf Header. find the sections names
76     strtab = self.shdrs[self.header.e_shstrndx].content
77
78     for sh in self.shdrs:
79       sh.name = strtab[int(sh.sh_name)]
80       self.sections[sh.name] = sh
81
82       # And resolve names in the section itself
83       sh.resolve_names()
84
85
86   def find_symbols(self):
87     for sh in self.shdrs:
88       if sh.sh_type == SHT_SYMTAB:
89         symtab = sh.content.symtab
90
91         for symbol in symtab:
92           if symbol.st_type == STT_FILE:
93             continue
94           if symbol.st_shndx == SHN_ABS:
95             continue
96           if symbol.st_shndx == SHN_UNDEF:
97             if symbol.name:
98               self.undefined_symbols.append(symbol.name)
99             continue
100
101           target_section = self.shdrs[symbol.st_shndx]
102
103           symbol_name = symbol.name
104           value = symbol.st_value
105           bind = symbol.st_binding
106
107           # We got a name, a target section, and an offset in the section
108           if symbol.st_binding == STB_LOCAL:
109             if symbol.st_type == STT_SECTION:
110               symbol_name = target_section.name
111             self.local_symbols[symbol_name] = (target_section, value)
112           else:
113             self.global_symbols[symbol_name] = (target_section, value)
114
115   def apply_relocation(self, all_global_symbols):
116     # find relocation tables
117     relocations = [sh for sh in self.shdrs if sh.sh_type in [SHT_REL, SHT_RELA]]
118     for sh in relocations:
119       target = sh.target.content
120
121       for reloc in sh.content.relatab:
122         
123         if reloc.symbol.st_shndx == SHN_UNDEF:
124           # This is an extern symbol, find it in all_global_symbols
125           sym_address = all_global_symbols[reloc.symbol.name]
126           print "0x%x" % sym_address
127         else:
128           # source == in which section it is defined
129           source = self.shdrs[reloc.symbol.st_shndx].content
130           sym_address = source.virt_addr + reloc.symbol.st_value
131
132         target_ba = target.data # The actual BinArray that we'll modify
133         pc_address = target.virt_addr + reloc.r_offset
134
135         if reloc.r_type == R_X86_64_64:
136           format = "<Q" # Direct 64 bit address
137           target_value = sym_address + reloc.r_addend
138         elif reloc.r_type == R_X86_64_PC32:
139           format = "<i" # PC relative 32 bit signed
140           target_value = sym_address + reloc.r_addend - pc_address
141         elif reloc.r_type == R_X86_64_32:
142           format = "<I" # Direct 32 bit zero extended
143           target_value = sym_address + reloc.r_addend
144         elif reloc.r_type == R_X86_64_PC16:
145           format = "<h" # 16 bit sign extended pc relative
146           target_value = sym_address + reloc.r_addend - pc_address
147         elif reloc.r_type == R_X86_64_16:
148           format = "<H" # Direct 16 bit zero extended
149           target_value = sym_address + reloc.r_addend
150         elif reloc.r_type == R_X86_64_PC8:
151           format = "b" # 8 bit sign extended pc relative
152           target_value = sym_address + reloc.r_addend - pc_address
153         elif reloc.r_type == R_X86_64_8:
154           format = "b" # Direct 8 bit sign extended
155           target_value = sym_address + reloc.r_addend
156         else:
157           print "Unsupported relocation type: %s" % reloc.r_type
158           exit(1)
159
160         d = BinArray(struct.pack(format, target_value))
161         start = reloc.r_offset
162         end = start + len(d)
163         target_ba[start:end] = d
164
165
166   def add_phdr(self, phdr):
167     self.phdrs.append(phdr)
168     self.header.e_phnum = len(self.phdrs)
169     phdr.owner = self
170
171   def add_segment(self, segment):
172     self.segments.append(segment)
173
174   def layout(self, base_vaddr):
175     """Do the actual layout for final executable."""
176
177     virt_addr = base_vaddr
178     file_offset = 0
179     self.virt_addr = base_vaddr
180     self.file_offset = file_offset
181     for s in self.segments:
182         virt_addr += s.align
183         s.virt_addr = virt_addr
184         s.file_offset = file_offset
185         s.layout()
186         virt_addr += s.logical_size
187         file_offset += s.physical_size
188
189   def toBinArray(self):
190     ba = BinArray()
191     for s in self.segments:
192       ba.extend(s.toBinArray())
193     return ba
194
195
196 #--------------------------------------------------------------------------
197 #  Elf file header
198 #--------------------------------------------------------------------------
199
200 class Elf64_eident(object):
201   """Detailed representation for the Elf identifier."""
202   format = "16B"
203   size = struct.calcsize(format)
204   physical_size = size
205   logical_size = size
206
207   def __init__(self, rawdata=None):
208     object.__init__(self)
209     if rawdata:
210       self.fromBinArray(rawdata)
211
212   def fromBinArray(self, rawdata):
213     t = struct.unpack(self.format, rawdata)
214     self.ei_magic = rawdata[:4]
215     self.ei_class = ElfClass(rawdata[4])
216     self.ei_data = ElfData(rawdata[5])
217     self.ei_version = ElfVersion(rawdata[6])
218     self.ei_osabi = ElfOsAbi(rawdata[7])
219     self.ei_abiversion = 0
220     self.ei_pad = [0, 0, 0, 0, 0, 0, 0]
221
222   def make_default_amd64(self):
223     self.ei_magic = BinArray([0x7f, 0x45, 0x4c, 0x46])
224     self.ei_class = ELFCLASS64
225     self.ei_data = ELFDATA2LSB
226     self.ei_version = EV_CURRENT
227     self.ei_osabi = ELFOSABI_SYSV
228     self.ei_abiversion = 0
229     self.ei_pad = [0, 0, 0, 0, 0, 0, 0]
230
231   def toBinArray(self):
232     ba = BinArray(self.ei_magic)
233     ba.append(self.ei_class)
234     ba.append(self.ei_data)
235     ba.append(self.ei_version)
236     ba.append(self.ei_osabi)
237     ba.append(self.ei_abiversion)
238     ba.extend(self.ei_pad)
239     return ba
240
241
242 class Elf64_Ehdr(object):
243   """Elf file header"""
244   format = "<16B 2H I 3Q I 6H"
245   size = struct.calcsize(format)
246   physical_size = size
247   logical_size = size
248   
249   def __init__(self, rawdata=None):
250     object.__init__(self)
251     self.e_ident = Elf64_eident()
252     self.e_type = ET_NONE
253     self.e_machine = EM_X86_64
254     self.e_version = EV_CURRENT
255     self.e_entry = 0
256     self.e_phoff = 0
257     self.e_shoff = 0
258     self.e_flags = 0
259     self.e_ehsize = self.size
260     self.e_phentsize = Elf64_Phdr.size
261     self.e_phnum = 0
262     self.e_shentsize = Elf64_Shdr.size
263     self.e_shnum = 0
264     self.e_shstrndx = 0
265     if rawdata:
266       self.fromBinArray(rawdata)
267
268   def fromBinArray(self, rawdata):
269     t = struct.unpack(self.format, rawdata)
270     self.e_ident = Elf64_eident(BinArray(rawdata[:16]))
271     self.e_type = ElfType(t[16])
272     self.e_machine = ElfMachine(t[17])
273     self.e_version = ElfVersion(t[18])
274     self.e_entry = t[19]
275     self.e_phoff = t[20]
276     self.e_shoff = t[21]
277     self.e_flags = t[22]
278     self.e_ehsize = t[23]
279     self.e_phentsize = t[24]
280     self.e_phnum = t[25]
281     self.e_shentsize = t[26]
282     self.e_shnum = t[27]
283     self.e_shstrndx = t[28]
284
285   def toBinArray(self):
286     # Build a list from e_ident and all other fields, to feed struct.pack.
287     values = self.e_ident.toBinArray().tolist()
288     values.extend([self.e_type, self.e_machine, self.e_version, self.e_entry,
289       self.e_phoff, self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize,
290       self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx])
291     res = struct.pack(self.format, *values)
292     return BinArray(res)
293
294   def layout(self):
295     pass
296
297
298 #--------------------------------------------------------------------------
299 #  Elf Sections
300 #--------------------------------------------------------------------------
301
302 class Elf64_Shdr(object):
303   """Elf64 section header."""
304   format = "<2I 4Q 2I 2Q"
305   size = struct.calcsize(format)
306   physical_size = size
307   logical_size = size
308   
309   def __init__(self, index=None, rawdata=None):
310     object.__init__(self)
311     self.index = index
312     if rawdata:
313       self.fromBinArray(rawdata)
314
315   def fromBinArray(self, rawdata):
316     t = struct.unpack(self.format, rawdata)
317     self.sh_name = t[0]
318     self.sh_type = ElfShType(t[1])
319     self.sh_flags = t[2]
320     self.sh_addr = t[3]
321     self.sh_offset = t[4]
322     self.sh_size = t[5]
323     self.sh_link = t[6]
324     self.sh_info = t[7]
325     self.sh_addralign = t[8]
326     self.sh_entsize = t[9]
327
328   def resolve_names(self):
329     self.content.resolve_names(self.owner)
330
331   @nested_property
332   def content():
333     def fget(self):
334       return self._content
335     def fset(self, data):
336       """Use the Section factory to get the subclass corresponding to the
337          session type specified in this header)."""
338       self._content = Section(self, data)
339     return locals()
340
341 # For sections that contain elements of specific types :
342
343 class Elf64_Sym(object):
344   """Symbol Table entry"""
345   format = "<I 2B H 2Q "
346   entsize = struct.calcsize(format)
347   def __init__(self, rawdata=None):
348     object.__init__(self)
349     if rawdata:
350       self.fromBinArray(rawdata)
351
352   @nested_property
353   def st_binding():
354     def fget(self):
355       return ElfSymbolBinding((self.st_info >> 4) & 0x0f)
356     def fset(self, value):
357       self.st_info = (((value & 0x0f) << 4) | (self.st_info & 0x0f))
358     return locals()
359
360   @nested_property
361   def st_type():
362     def fget(self):
363        return ElfSymbolType(self.st_info & 0x0f)
364     def fset(self, value):
365       self.st_info = ((self.st_info & 0xf0) | (value & 0x0f))
366     return locals()
367
368   @nested_property
369   def st_visibility():
370     def fget(self):
371       return ElfSymbolVisibility(self.st_other & 0x03)
372     def fset(self, value):
373       self.st_other = ((self.st_other & 0xfc) | (value & 0x03))
374     return locals()
375
376   def fromBinArray(self, rawdata):
377     t = struct.unpack(self.format, rawdata)
378     self.st_name = t[0] # index in the strtab pointed by sh_link
379     self.st_info = t[1]
380     self.st_other = t[2]
381     self.st_shndx = ElfSectionIndex(t[3])
382     self.st_value = t[4]
383     self.st_size = t[5]
384
385
386 class Elf64_Rel(object):
387   format = "<2Q"
388   def __init__(self, rawdata=None):
389     object.__init__(self)
390     self.r_addend = 0 # No addend in a Rel.
391     if rawdata:
392       self.fromBinArray(rawdata)
393
394   def fromBinArray(sef, rawdata):
395     t = struct.unpack(self.format, rawdata)
396     self.r_offset = t[0]
397     self.r_info = t[1]
398
399   @nested_property
400   def r_sym():
401     def fget(self):
402       return (self.r_info >> 32) & 0xffffffff
403     def fset(self, value):
404       self.r_info = ((value & 0xffffffff) << 32) | (self.r_info & 0xffffffff)
405     return locals()
406
407   @nested_property
408   def r_type():
409     def fget(self):
410       return Amd64Relocation(self.r_info & 0xffffffff)
411     def fset(self, value):
412       self.r_info = (self.r_info & 0xffffffff00000000) | (value & 0xffffffff)
413     return locals()
414
415
416 class Elf64_Rela(Elf64_Rel):
417   format = "<2Q q"
418   def __init__(self, rawdata=None):
419     Elf64_Rel.__init__(self, rawdata)
420
421   def fromBinArray(self, rawdata):
422     t = struct.unpack(self.format, rawdata)
423     self.r_offset = t[0]
424     self.r_info = t[1]
425     self.r_addend = t[2]
426
427
428 class Elf64_Dyn(object):
429   format = "<2Q"
430   size = struct.calcsize(format)
431   def __init__(self, tag, value):
432     object.__init__(self)
433     self.d_tag = tag
434     self.d_val = value
435
436   @nested_property
437   def d_ptr():
438     def fget(self):
439       return self.d_val
440     def fset(self, value):
441       self.d_val = value
442     return locals()
443
444
445 # Sections types :
446
447 def Section(shdr, data=None):
448   """A section factory"""
449   dataclass = {
450     SHT_NULL:           SNull,
451     SHT_PROGBITS:       SProgBits,
452     SHT_SYMTAB:         SSymtab,
453     SHT_STRTAB:         SStrtab,
454     SHT_RELA:           SRela,
455     SHT_HASH:           SHash,
456     SHT_DYNAMIC:        SDynamic,
457     SHT_NOTE:           SNote,
458     SHT_NOBITS:         SNobits,
459     SHT_REL:            SRel,
460     SHT_SHLIB:          SShlib,
461     SHT_DYNSYM:         SDynsym
462   }
463   if shdr.sh_type in dataclass:
464     return dataclass[shdr.sh_type](shdr, data)
465   else:
466     return BaseSection(shdr, data)
467
468
469 class BaseSection(object):
470   def __init__(self, shdr, data=None):
471     object.__init__(self)
472     self.data = None
473     self.header = shdr
474     if data:
475       self.fromBinArray(data)
476
477   def fromBinArray(self, data):
478     self.data = data
479
480   def toBinArray(self):
481     if self.data:
482       return self.data
483     else:
484       return BinArray()
485
486   def resolve_names(self, elf):
487     """Nothing to resolve."""
488     pass
489
490   @nested_property
491   def size():
492     def fget(self):
493       return len(self.data)
494     return locals()
495   physical_size = size
496   logical_size = size
497
498   def layout(self):
499     pass
500
501
502 class SNull(BaseSection):
503   def __init__(self, shdr, data=None):
504     BaseSection.__init__(self, shdr, None)
505
506
507 class SProgBits(BaseSection):
508   def __init__(self, shdr, data=None):
509     BaseSection.__init__(self, shdr, data)
510
511
512 class SSymtab(BaseSection):
513   entsize = struct.calcsize(Elf64_Sym.format)
514   def __init__(self, shdr, data=None):
515     self.symtab = []
516     BaseSection.__init__(self, shdr, data)
517
518   def fromBinArray(self, data):
519     BaseSection.fromBinArray(self, data)
520     nument = len(data) / self.entsize
521     for i in range(nument):
522       start = i * self.entsize
523       end = i * self.entsize + self.entsize
524       self.symtab.append(Elf64_Sym(data[start:end]))
525
526   def resolve_names(self, elf):
527     # For a symtab, the strtab is indicated by sh_link
528     strtab = elf.shdrs[self.header.sh_link].content
529     # Resolve for all symbols in the table
530     for sym in self.symtab:
531       sym.name = strtab[sym.st_name]
532
533   def __getitem__(self, key):
534     return self.symtab[key]
535
536
537 class SStrtab(BaseSection):
538   def __init__(self, shdr, data=None):
539     self.strtab = {}
540     BaseSection.__init__(self, shdr, data)
541
542   def fromBinArray(self, data):
543     BaseSection.fromBinArray(self, data)
544     itab = data.tostring().split('\0')
545     i = 0
546     for sname in itab:
547       self.strtab[i] = sname
548       i += len(sname) + 1
549
550   def __getitem__(self, key):
551     if key in self.strtab:
552       return self.strtab[key]
553     else:
554       v = self.data[key:].tostring().split('\0')[0]
555       self.strtab[key] = v
556       return v
557
558   def iteritems(self):
559     return self.strtab.iteritems()
560
561
562 class SRela(BaseSection):
563   entsize = struct.calcsize(Elf64_Rela.format)
564   def __init__(self, shdr, data=None):
565     self.relatab = []
566     BaseSection.__init__(self, shdr, data)
567
568   def fromBinArray(self, data):
569     BaseSection.fromBinArray(self, data)
570     nument = len(data) / self.entsize
571     for i in range(nument):
572       start = i * self.entsize
573       end = i * self.entsize + self.entsize
574       self.relatab.append(Elf64_Rela(data[start:end]))
575
576   def resolve_names(self, elf):
577     """Badly named, this wil resolve to a symtab entry..."""
578     # sh_link leads to the symtab
579     self.symtab = elf.shdrs[self.header.sh_link].content
580     # sh_info links to the section on which the relocation applies
581     self.header.target = elf.shdrs[self.header.sh_info]
582     for r in self.relatab:
583       r.symbol = self.symtab[r.r_sym]
584       
585     
586
587 class SHash(BaseSection):
588   pass
589
590
591 class SDynamic(BaseSection):
592   pass
593
594
595 class SNote(BaseSection):
596   pass
597
598
599 class SNobits(BaseSection):
600   size = 0
601   physical_size = 0
602
603   @nested_property
604   def logical_size():
605     def fget(self):
606       return self.header.sh_size
607     return locals()
608
609   def toBinArray(self):
610     return BinArray()
611
612 class SRel(BaseSection):
613   pass
614
615
616 class SShlib(BaseSection):
617   pass
618
619
620 class SDynsym(SSymtab):
621   pass
622
623
624 class Elf64_Phdr(object):
625   format = "<2I 6Q"
626   size = struct.calcsize(format)
627   physical_size = size
628   logical_size = size
629
630   def __init__(self):
631     object.__init__(self)
632     self.p_type = PT_NULL
633     self.p_flags = PF_X + PF_W + PF_R
634     self.p_offset = 0
635     self.p_vaddr = 0
636     self.p_paddr = 0
637     self.p_filesz = 0
638     self.p_memsz = 0
639     self.p_align = 1
640     #self.content = []
641     #self.nobits = []
642
643   def toBinArray(self):
644     res = struct.pack(self.format, self.p_type, self.p_flags, self.p_offset,
645       self.p_vaddr, self.p_paddr, self.p_filesz, self.p_memsz, self.p_align)
646     return BinArray(res)
647
648   def layout(self):
649     pass
650
651   #def add_content(self, content):
652   #  self.content.append(content)
653
654   #def add_empty_content(self, content):
655   #  self.nobits.append(content)
656
657   #@nested_property
658   #def content_size():
659   #  def fget(self):
660   #    return sum(s.sh_size for s in self.content)
661   #  return locals()
662
663
664 class BaseSegment(object):
665   def __init__(self, align=0):
666     object.__init__(self)
667     self.align = align
668     self.content = []
669
670   def add_content(self, content):
671     self.content.append(content)
672
673   def toBinArray(self):
674     ba = BinArray()
675     for c in self.content:
676       ba.extend(c.toBinArray())
677     return ba
678
679   @nested_property
680   def size():
681     def fget(self):
682       return sum(c.size for c in self.content)
683     return locals()
684   physical_size = size
685   logical_size = size
686
687
688 class TextSegment(BaseSegment):
689   def __init__(self, align=0):
690     BaseSegment.__init__(self, align)
691
692   def layout(self):
693     virt_addr = self.virt_addr
694     file_offset = self.file_offset
695     for i in self.content:
696       i.virt_addr = virt_addr
697       i.file_offset = file_offset
698       i.layout()
699       virt_addr += i.logical_size
700       file_offset += i.physical_size
701
702
703 class DataSegment(BaseSegment):
704   def __init__(self, align=0):
705     BaseSegment.__init__(self, align)
706     self.nobits = []
707
708   def add_nobits(self, content):
709     self.nobits.append(content)
710
711   def layout(self):
712     virt_addr = self.virt_addr
713     file_offset = self.file_offset
714     for i in self.content:
715       i.virt_addr = virt_addr
716       i.file_offset = file_offset
717       i.layout()
718       virt_addr += i.logical_size
719       file_offset += i.physical_size
720     for i in self.nobits:
721       i.virt_addr = virt_addr
722       i.file_offset = 0
723       i.layout()
724       virt_addr += i.logical_size
725
726   @nested_property
727   def logical_size():
728     def fget(self):
729       return self.physical_size + sum(c.logical_size for c in self.nobits)
730     return locals()
731
732
733
734 class PStrtab(object):
735   def __init__(self):
736     object.__init__(self)
737     self.table = []
738     self.virt_addr = None
739
740   def append(self, string):
741     if len(self.table):
742       offset = self.table[-1][0]
743       offset += len(self.table[-1][1])
744     else:
745       offset = 0
746     new_str = string + '\0'
747     self.table.append((offset, new_str))
748     return offset
749
750   @nested_property
751   def size():
752     def fget(self):
753       return (self.table[-1][0] + len(self.table[-1][1]))
754     return locals()
755   physical_size = size
756   logical_size = size
757
758   def toBinArray(self):
759     ba = BinArray()
760     for s in (i[1] for i in self.table):
761       ba.fromstring(s)
762     return ba
763
764   def layout(self):
765     pass
766
767
768 class Dynamic(object):
769   def __init__(self):
770     object.__init__(self)
771     self.dyntab = []
772     self.strtab = PStrtab()
773
774   @nested_property
775   def size():
776     def fget(self):
777       # End the table with a DT_NULL without associated value.
778       return (Elf64_Dyn.size * len(self.dyntab) + struct.calcsize("Q"))
779     return locals()
780   physical_size = size
781   logical_size = size
782
783   def add_shlib(self, shlib):
784     offset = self.strtab.append(shlib)
785     self.dyntab.append((DT_NEEDED, offset))
786
787   def add_symtab(self, vaddr):
788     self.dyntab.append((DT_SYMTAB, vaddr))
789
790   def add_debug(self):
791     self.dyntab.append((DT_DEBUG, 0))
792
793   def layout(self):
794     # Adjust the address of the strtab, if 
795     if self.strtab.virt_addr is None:
796       print "Ooops, strtab's address is not known yet. Aborting."
797       exit(1)
798     else:
799       self.dyntab.append((DT_STRTAB, self.strtab.virt_addr))
800
801   @nested_property
802   def dt_debug_address():
803     def fget(self):
804       for i, d in enumerate(self.dyntab):
805         if d[0] == DT_DEBUG:
806           return self.virt_addr + (i*16 + 8)
807     return locals()
808     
809
810   def toBinArray(self):
811     ba = BinArray()
812     for i in self.dyntab:
813       s = struct.pack("<2Q", i[0], i[1])
814       ba.fromstring(s)
815     null = struct.pack("<Q", DT_NULL)
816     ba.fromstring(null)
817     return ba
818
819
820 class Interpreter(object):
821   default_interpreter = "/lib64/ld-linux-x86-64.so.2"
822
823   def __init__(self, interpreter=None):
824     object.__init__(self)
825     if interpreter:
826       self.interpreter = interpreter
827     else:
828       self.interpreter = self.default_interpreter
829
830   @nested_property
831   def size():
832     def fget(self):
833       # Null terminated
834       return len(self.interpreter) + 1
835     return locals()
836   physical_size = size
837   logical_size = size
838
839   def toBinArray(self):
840     ba = BinArray(self.interpreter)
841     ba.append(0)
842     return ba
843
844   def layout(self):
845     pass