summaryrefslogtreecommitdiff
path: root/tools/libdol2asm/data/symbol.py
blob: 9a75d16bb69e9f029141f8bb99b90c466d87cde1 (plain)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283

from dataclasses import dataclass, field

from .. import util
from ..builder import AsyncBuilder
from ..types import *
from .identifier import *

@dataclass(frozen=True)
class AddressRange:
    start: int
    end: int

    def __contains__(self, value):
        return value >= self.start and value < self.end

@dataclass
class ReferenceCount:
    total: int = 0
    static: int = 0
    extern: int = 0
    rel: int = 0

    def add_reference(self, referencee, referencer, count):
        self.total += count
        if referencer:
            if referencee._module != referencer._module:
                self.rel += count
            elif (referencee._library == referencer._library and
                  referencee._translation_unit == referencer._translation_unit):
                self.static += count
            else:
                self.extern += count
        else:
            self.extern += count

    def make_static(self):
        self.total = 1
        self.static = 1
        self.extern = 0
        self.rel = 0


@dataclass(eq=False)
class Symbol:
    identifier: Identifier
    addr: int
    size: int
    padding: int = 0
    alignment: int = 0
    reference_count: ReferenceCount = field(default_factory=ReferenceCount)
    implicit_reference_count: ReferenceCount = field(default_factory=ReferenceCount)
    sda_hack_reference_count: ReferenceCount = field(
        default_factory=ReferenceCount)
    require_forward_reference: bool = False
    data_type: Type = None
    source: str = None
    force_section: str = None
    _module: str = None
    _library: str = None
    _translation_unit: str = None
    _section: str = None
    alignment: int = 0
    relative_addr: int = -1
    template_index: int = -1

    demangled_name: NamedType = None
    references: Set[int] = field(default_factory=set)
    implicit_references: Set[int] = field(default_factory=set)
    is_reachable: bool = False

    def __hash__(self):
        return hash(self.addr)

    def __eq__(self, other):
        if not hasattr(self, 'addr'):
            return True
        return self.addr == other.addr and self.size == other.size

    @property
    def start(self):
        return self.addr

    @property
    def end(self):
        return self.addr + self.size

    @property
    def offset(self):
        return self.addr - self.section.addr

    @property
    def label(self):
        return self.identifier.label

    @property
    def is_static(self):
        return False

    @property
    def has_body(self):
        return True

    @property
    def has_class(self):
        return self.demangled_name and self.demangled_name.has_class

    @property
    def has_template(self):
        return self.demangled_name and self.demangled_name.has_template

    @property
    def uses_class_template(self):
        return self.demangled_name and self.demangled_name.has_template

    @property
    def is_demangled(self):
        return self.demangled_name != None

    @property
    def requires_force_active(self):
        return False

    def add_reference(self, referencer, count=1):
        self.reference_count.add_reference(self, referencer, count)

    def add_implicit_reference(self, referencer, count=1):
        self.implicit_reference_count.add_reference(self, referencer, count)

    def add_sda_hack(self, referencer, count=1):
        self.sda_hack_reference_count.add_reference(self, referencer, count)

    def valid_reference(self, addr):
        return addr == self.addr

    def cpp_reference(self, accessor, addr):
        if addr != self.addr:
            raise Dol2ZelException(
                f"invalid reference addr 0x{addr:08X} for {type(self).__name__}\n{self}")
        return f"&{self.identifier.label}"

    def cpp_load(self, accessor, addr):
        if addr != self.addr:
            raise Dol2ZelException(
                f"invalid reference addr 0x{addr:08X} for {type(self).__name__}\n{self}")
        return f"{self.identifier.label}"

    def asm_reference(self, addr):
        if addr != self.addr:
            return None
        return self.identifier.label

    def gather_references(self, context, valid_range):
        pass

    def get_reference_information(self, context, symbol_table):
        pass

    def types(self):
        return set()

    def set_mlts(self, module: int, library: str, translation_unit: str, section: str):
        self._module = module
        self._library = library
        self._translation_unit = translation_unit
        self._section = section

    async def export_section_header(self, builder: AsyncBuilder):
        if self._section == ".extab":
            await builder.write("#pragma section \"extab_\"")
        if self._section == ".extabindex":
            await builder.write("#pragma section \"extabindex_\"")
        elif self._section == ".ctors":
            if self.identifier.label == "__init_cpp_exceptions_reference":
                #await builder.write("#pragma section \".ctors$10\"")
                #await builder.write_nonewline("__declspec(section \".ctors$10\") ")
                await builder.write_nonewline("SECTION_CTORS10 ")
            elif self.identifier.label == "_ctors":
                #await builder.write("#pragma section \".ctors$15\"")
                #await builder.write_nonewline("__declspec(section \".ctors$15\") ")
                await builder.write_nonewline("SECTION_CTORS15 ")
        elif self._section == ".dtors":
            if self.identifier.label == "__destroy_global_chain_reference":
                #await builder.write("#pragma section \".dtors$10\"")
                #await builder.write_nonewline("__declspec(section \".dtors$10\") ")
                await builder.write_nonewline("SECTION_DTORS10 ")
            elif self.identifier.label == "__fini_cpp_exceptions_reference":
                #await builder.write("#pragma section \".dtors$15\"")
                #await builder.write_nonewline("__declspec(section \".dtors$15\") ")
                await builder.write_nonewline("SECTION_DTORS15 ")
            elif self.identifier.label == "__dtors_null_terminator":
                #await builder.write("#pragma section \".dtors$15\"")
                #await builder.write_nonewline("__declspec(section \".dtors$15\") ")
                await builder.write_nonewline("SECTION_DTORS15 ")
            elif self.identifier.label == "_dtors":
                await builder.write_nonewline("SECTION_DTORS10 ")
        elif self.force_section:
            if self.force_section == '.bss':
                await builder.write_nonewline("SECTION_BSS ")
            else:
                assert False
        else:
            await builder.write_nonewline("extern \"C\" ")

    async def export_section(self, builder: AsyncBuilder):
        section = ""

        if self._section == ".data":
            section = "SECTION_DATA "
        elif self._section == ".sdata":
            section = "SECTION_SDATA "
        elif self._section == ".sdata2":
            section = "SECTION_SDATA2 "
        # elif self._section == ".bss":
        #    section = "SECTION_BSS "
        # elif self._section == ".sbss":
        #    section = "SECTION_SBSS "
        elif self._section == ".sbss2":
            section = "SECTION_SBSS2 "
        elif self._section == ".init":
            section = "SECTION_INIT "
        elif self._section == ".rodata":
            section = "SECTION_RODATA "
        elif self._section == ".extab":
            await builder.write_nonewline("SECTION_EXTAB ")
        elif self._section == ".extabindex":
            await builder.write_nonewline("SECTION_EXTABINDEX ")
        elif self._section == ".ctors":
            if self.identifier.label == "__init_cpp_exceptions_reference":
                #section = "__declspec(section \".ctors$10\") "
                section = "SECTION_CTORS10 "
            elif self.identifier.label == "_ctors":
                #section = "__declspec(section \".ctors$15\") "
                section = "SECTION_CTORS15 "
        elif self._section == ".dtors":
            if self.identifier.label == "__destroy_global_chain_reference":
                #section = "__declspec(section \".dtors$10\") "
                section = "SECTION_DTORS10 "
            elif self.identifier.label == "__fini_cpp_exceptions_reference":
                #section = "__declspec(section \".dtors$15\") "
                section = "SECTION_DTORS15 "
            elif self.identifier.label == "__dtors_null_terminator":
                #section = "__declspec(section \".dtors$15\") "
                section = "SECTION_DTORS15 "
            elif self.identifier.label == "_dtors":
                section = "SECTION_DTORS10 "
        await builder.write_nonewline(section)

    async def export_extern(self, builder: AsyncBuilder):
        await builder.write_nonewline(f"extern ")

    async def export_static(self, builder: AsyncBuilder):
        await builder.write_nonewline(f"static ")

    async def export_force_active(self, builder: AsyncBuilder):
        await builder.write_nonewline(f"__declspec(forceactive) ")

    async def export_readonly(self, builder: AsyncBuilder): 
        if self._section == ".rodata":
            await builder.write_nonewline(f"const ")
        elif self._section == ".extab":
            await builder.write_nonewline(f"const ")
        elif self._section == ".extabindex":
            await builder.write_nonewline(f"const ")
        elif self._section == ".ctors":
            await builder.write_nonewline(f"const ")
        elif self._section == ".dtors":
            await builder.write_nonewline(f"const ")

    async def export_declaration_head(self, builder: AsyncBuilder):
        assert False

    async def export_declaration_body(self, builder: AsyncBuilder):
        assert False

    async def export_declaration(self, exporter, builder: AsyncBuilder):
        await self.export_declaration_head(exporter, builder)
        await self.export_declaration_body(exporter, builder)

    async def export_u8_data(self, builder: AsyncBuilder, data: bytearray):
        for chunk in util.chunks(data, 16):
            line = ", ".join([f"0x{x:02X}" for x in chunk])
            await builder.write(f"\t{line},")