1
1
import argparse
2
2
import shutil
3
+ from subprocess import check_output
3
4
from elftools .elf .elffile import ELFFile
4
5
from elftools .elf .sections import SymbolTableSection
5
6
from typing import TextIO
6
7
import math
7
8
import os
8
9
from pathlib import Path
9
- from pycparser import c_ast , parse_file , c_generator
10
+ from pycparser import c_ast , c_generator , CParser
10
11
11
12
from dino .dll import DLL
12
13
from dino .dll_analysis import get_all_dll_functions
27
28
28
29
# 0x8001B4F0-0x8001C8D4 is handwritten assembly that trips up recomp, split it into a bunch of
29
30
# functions that don't technically exist to get recomp working. This will basically make problematic
30
- # conditional branches turn into condotional tail calls into these fake functions
31
+ # conditional branches turn into conditional tail calls into these fake functions
31
32
# Note: Some of the fake functions must overlap fake functions below them
32
33
0x8001B4F0 : { "name" : "func_8001B4F0" , "size" : 0x200 },
33
34
0x8001B6F0 : { "name" : "func_8001B6F0" , "size" : 0x510 },
@@ -152,21 +153,26 @@ def gen_core_syms(syms_toml: TextIO, datasyms_toml: TextIO):
152
153
153
154
datasyms_toml .write ("]\n " )
154
155
155
- PYCPARSER_CPP_ARGS = [
156
- '-D_LANGUAGE_C' ,
157
- '-D_MIPS_SZLONG=32' ,
158
- '-DF3DEX_GBI_2' ,
159
- '-Iinclude'
156
+ GCC_PREPROCESS_CMD = [
157
+ "gcc" ,
158
+ "-nostdinc" ,
159
+ "-E" ,
160
+ "-D_LANGUAGE_C" ,
161
+ "-D_MIPS_SZLONG=32" ,
162
+ "-DF3DEX_GBI_2" ,
163
+ "-Iinclude"
160
164
]
161
165
166
+ c_gen = c_generator .CGenerator ()
167
+ c_parser = CParser ()
168
+
162
169
def gen_dll_recomp_header (header : TextIO ,
163
170
c_source_paths : list [Path ],
164
171
symbol_renames : "dict[str, str]" ):
165
172
# Parse C source
166
173
includes : list [str ] = []
167
174
declarations : list [tuple [str , str ]] = []
168
-
169
- c_gen = c_generator .CGenerator ()
175
+ found_symbols : "set[str]" = set ()
170
176
171
177
for c_source_path in c_source_paths :
172
178
# Get includes
@@ -177,17 +183,19 @@ def gen_dll_recomp_header(header: TextIO,
177
183
includes .append (line [line .index (" " ) + 1 :])
178
184
179
185
# Get declarations
180
- ast : c_ast . FileAST = parse_file ( str (c_source_path ), use_cpp = True ,
181
- cpp_args = PYCPARSER_CPP_ARGS )
186
+ preprocessed_text = check_output ( GCC_PREPROCESS_CMD + [ str (c_source_path )], universal_newlines = True )
187
+ ast : c_ast . FileAST = c_parser . parse ( preprocessed_text )
182
188
183
189
for child in ast :
184
190
if isinstance (child , c_ast .Decl ):
185
191
original = child .name
192
+ if original in found_symbols :
193
+ continue
186
194
rename = symbol_renames .get (original )
187
195
if rename != None :
188
196
# Turn data decl into an extern
189
197
type = child .type
190
- if isinstance (type , c_ast .ArrayDecl ) or isinstance (type , c_ast .PtrDecl ):
198
+ if isinstance (type , c_ast .ArrayDecl ) or isinstance (type , c_ast .PtrDecl ) or isinstance ( type , c_ast . FuncDecl ) :
191
199
type = type .type
192
200
if not isinstance (type , c_ast .TypeDecl ):
193
201
continue
@@ -201,8 +209,11 @@ def gen_dll_recomp_header(header: TextIO,
201
209
alias = "#define {} {}" .format (original , rename )
202
210
203
211
declarations .append ((decl , alias ))
212
+ found_symbols .add (original )
204
213
elif isinstance (child , c_ast .FuncDef ):
205
214
original = child .decl .name
215
+ if original in found_symbols :
216
+ continue
206
217
rename = symbol_renames .get (original )
207
218
if rename != None :
208
219
# Turn func def into an extern decl
@@ -217,6 +228,7 @@ def gen_dll_recomp_header(header: TextIO,
217
228
alias = "#define {} {}" .format (original , rename )
218
229
219
230
declarations .append ((decl , alias ))
231
+ found_symbols .add (original )
220
232
221
233
# Write
222
234
header .write ("#ifndef _DLL_29_INTERNAL_H\n " )
@@ -249,11 +261,13 @@ def scan_dll_elf(
249
261
st_info_type = sym .entry ["st_info" ]["type" ]
250
262
st_info_bind = sym .entry ["st_info" ]["bind" ]
251
263
252
- if st_info_type != "STT_FUNC" and st_info_type != "STT_OBJECT" :
264
+ maybe_unref_static_func = st_info_type == "STT_NOTYPE" and st_shndx == "SHN_ABS"
265
+
266
+ if st_info_type != "STT_FUNC" and st_info_type != "STT_OBJECT" and not maybe_unref_static_func :
253
267
continue
254
268
if st_shndx == "SHN_UNDEF" :
255
269
continue
256
- if st_info_bind != "STB_LOCAL" and size == 0 :
270
+ if st_info_bind != "STB_LOCAL" and size == 0 and not maybe_unref_static_func :
257
271
continue
258
272
if value & 0x80000000 :
259
273
# External symbol reference, already covered by core syms
@@ -276,9 +290,8 @@ def scan_dll_elf(
276
290
277
291
vram = dll_vram + sec_offset + value
278
292
279
- if st_info_type == "STT_FUNC" :
293
+ if st_info_type == "STT_FUNC" or maybe_unref_static_func :
280
294
# Function
281
-
282
295
func_info = vrams_to_funcs .get (vram )
283
296
if func_info == None :
284
297
print ("Failed to find DLL {} func {} at {:0X} ({:0X})"
0 commit comments