File: section.py

package info (click to toggle)
python-peachpy 0.0~git20211013.257881e-1.1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 2,452 kB
  • sloc: python: 29,286; ansic: 54; makefile: 44; cpp: 31
file content (162 lines) | stat: -rw-r--r-- 5,638 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# This file is part of PeachPy package and is licensed under the Simplified BSD license.
# See license.rst for the full text of the license.


import six


class SectionFlags:
    # Section contains executable code
    code = 0x00000020
    # Section contains initialized data
    initialized_data = 0x00000040
    # Section contains uninitialized data
    uninitialized_data = 0x00000080
    # Section contains extended relocations
    extended_relocations = 0x01000000
    # Section can be discarded as needed
    discardable = 0x02000000
    # Section can not be cached
    uncached = 0x04000000
    # Section can not be pageable
    unpaged = 0x08000000
    # Section data can be shared between process instances
    shared = 0x10000000
    # Section contains executable data during process execution
    executable = 0x20000000
    # Section contains readable data during process execution
    readable = 0x40000000
    # Section contains writable data during process execution
    writable = 0x80000000


class Section(object):
    header_size = 40

    _alignment_flag_map = {
        1: 0x00100000,
        2: 0x00200000,
        4: 0x00300000,
        8: 0x00400000,
        16: 0x00500000,
        32: 0x00600000,
        64: 0x00700000,
        128: 0x00800000,
        256: 0x00900000,
        512: 0x00A00000,
        1024: 0x00B00000,
        2048: 0x00C00000,
        4096: 0x00D00000,
        8192: 0x00E00000
    }

    _flag_alignment_map = {flag: alignment for (alignment, flag) in six.iteritems(_alignment_flag_map)}

    _alignment_mask = 0x00F00000

    def __init__(self, name, flags, alignment=None):
        from peachpy.util import is_uint32
        if not isinstance(name, str):
            raise TypeError("Section name %s is not a string" % str(name))
        if not is_uint32(flags):
            raise TypeError("Flags %s are not representable as a 32-bit unsigned integer" % str(flags))

        super(Section, self).__init__()
        # Section name
        self.name = name
        # Flags for the section
        self.flags = (flags & ~Section._alignment_mask) | Section._alignment_flag_map[1]
        if alignment is not None:
            self.alignment = alignment

        self.relocations = list()
        self.content = bytearray()

    @property
    def content_size(self):
        return len(self.content)

    @property
    def alignment(self):
        return Section._flag_alignment_map.get(self.flags & Section._alignment_mask, 1)

    @alignment.setter
    def alignment(self, alignment):
        from peachpy.util import is_int
        if not is_int(alignment):
            raise TypeError("Alignment %s is not an integer" % str(alignment))
        if alignment < 0:
            raise ValueError("Alignment %d is not a positive integer" % alignment)
        if alignment & (alignment - 1) != 0:
            raise ValueError("Alignment %d is not a power of 2" % alignment)
        if alignment not in Section._alignment_flag_map:
            raise ValueError("Alignment %d exceeds maximum alignment (8192)" % alignment)
        self.flags = (self.flags & ~Section._alignment_mask) | Section._alignment_flag_map[alignment]

    def encode_header(self, encoder, name_index_map, offset, relocations_offset=None, address=None):
        from peachpy.encoder import Encoder
        assert isinstance(encoder, Encoder)
        assert isinstance(name_index_map, dict)

        if address is None:
            address = 0
        if relocations_offset is None:
            relocations_offset = 0
        line_numbers_offset = 0
        line_numbers_count = 0
        try:
            name_8_bytes = encoder.fixed_string(self.name, 8)
        except ValueError:
            name_index = name_index_map[self.name]
            name_8_bytes = encoder.fixed_string("/" + str(name_index), 8)
        return name_8_bytes + \
            encoder.uint32(self.content_size) + \
            encoder.uint32(address) + \
            encoder.uint32(self.content_size) + \
            encoder.uint32(offset) + \
            encoder.uint32(relocations_offset) + \
            encoder.uint32(line_numbers_offset) + \
            encoder.uint16(len(self.relocations)) + \
            encoder.uint16(line_numbers_count) + \
            encoder.uint32(self.flags)


class TextSection(Section):
    def __init__(self, name=".text", alignment=None):
        super(TextSection, self).__init__(name,
                                          SectionFlags.code | SectionFlags.readable | SectionFlags.executable,
                                          alignment)


class ReadOnlyDataSection(Section):
    def __init__(self, name=".rdata", alignment=None):
        super(ReadOnlyDataSection, self).__init__(name,
                                           SectionFlags.initialized_data | SectionFlags.readable,
                                           alignment)


class StringTable:
    def __init__(self):
        self._strings = dict()
        self.size = 4

    def add(self, string):
        import codecs

        if string in self._strings:
            return self._strings[string]
        else:
            string_index = self.size
            self._strings[string] = string_index
            bytestring = codecs.encode(string, "utf-8")
            self.size += len(bytestring) + 1
            return string_index

    def encode(self):
        import codecs
        import peachpy.encoder

        bytestring = peachpy.encoder.Encoder.uint32le(self.size)
        for string in sorted(self._strings, key=self._strings.get):
            bytestring += codecs.encode(string, "utf8") + b"\x00"
        return bytestring