2 * DLL symbol extraction
4 * Copyright 2000 Jon Griffiths
8 /* DOS/PE Header details */
9 #define DOS_HEADER_LEN 64
10 #define DOS_MAGIC 0x5a4d
11 #define DOS_PE_OFFSET 60
12 #define PE_HEADER_LEN 248
13 #define PE_MAGIC 0x4550
14 #define PE_COUNT_OFFSET 6
15 #define PE_EXPORTS_OFFSET 120
16 #define PE_EXPORTS_SIZE PE_EXPORTS_OFFSET + 4
17 #define SECTION_HEADER_LEN 40
18 #define SECTION_ADDR_OFFSET 12
19 #define SECTION_ADDR_SIZE SECTION_ADDR_OFFSET + 4
20 #define SECTION_POS_OFFSET SECTION_ADDR_SIZE + 4
21 #define ORDINAL_BASE_OFFSET 16
22 #define ORDINAL_COUNT_OFFSET 20
23 #define ORDINAL_NAME_OFFSET ORDINAL_COUNT_OFFSET + 16
24 #define EXPORT_COUNT_OFFSET 24
25 #define EXPORT_NAME_OFFSET EXPORT_COUNT_OFFSET + 8
27 /* Minimum memory needed to read both headers into a buffer */
28 #define MIN_HEADER_LEN (PE_HEADER_LEN * sizeof (unsigned char))
30 /* Normalise a pointer in the exports section */
31 #define REBASE(x) ((x) - exports)
34 typedef struct _dll_symbol {
39 static FILE *dll_file = NULL;
40 static dll_symbol *dll_symbols = NULL;
41 static size_t dll_num_exports = 0;
42 static size_t dll_num_ordinals = 0;
43 static int dll_ordinal_base = 0;
45 static dll_symbol *dll_current_symbol = NULL;
46 static unsigned int dll_current_export = 0;
48 /* Get a short from a memory block */
49 static inline size_t get_short (const char *mem)
51 return *((const unsigned char *)mem) +
52 (*((const unsigned char *)mem + 1) << 8);
55 /* Get an integer from a memory block */
56 static inline size_t get_int (const char *mem)
58 assert (sizeof (char) == (size_t)1);
59 return get_short (mem) + (get_short (mem + 2) << 16);
62 /* Compare symbols by ordinal for qsort */
63 static int symbol_cmp(const void *left, const void *right)
65 return ((dll_symbol *)left)->ordinal > ((dll_symbol *)right)->ordinal;
68 static void dll_close (void);
71 /*******************************************************************
74 * Open a DLL and read in exported symbols
76 void dll_open (const char *dll_name)
78 size_t code = 0, code_len = 0, exports, exports_len, count, symbol_data;
81 dll_file = open_file (dll_name, ".dll", "r");
85 /* Read in the required DOS and PE Headers */
86 if (!(buff = (char *) malloc (MIN_HEADER_LEN)))
87 fatal ("Out of memory");
89 if (fread (buff, DOS_HEADER_LEN, 1, dll_file) != 1 ||
90 get_short (buff) != DOS_MAGIC)
91 fatal ("Error reading DOS header");
93 if (fseek (dll_file, get_int (buff + DOS_PE_OFFSET), SEEK_SET) == -1)
94 fatal ("Error seeking PE header");
96 if (fread (buff, PE_HEADER_LEN, 1, dll_file) != 1 ||
97 get_int (buff) != PE_MAGIC)
98 fatal ("Error reading PE header");
100 exports = get_int (buff + PE_EXPORTS_OFFSET);
101 exports_len = get_int (buff + PE_EXPORTS_SIZE);
103 if (!exports || !exports_len)
104 fatal ("No exports in DLL");
106 if (!(count = get_short (buff + PE_COUNT_OFFSET)))
107 fatal ("No sections in DLL");
110 printf ("DLL has %d sections\n", count);
112 /* Iterate through sections until we find exports */
115 if (fread (buff, SECTION_HEADER_LEN, 1, dll_file) != 1)
116 fatal ("Section read error");
118 code = get_int (buff + SECTION_ADDR_OFFSET);
119 code_len = get_int (buff + SECTION_ADDR_SIZE);
121 if (code <= exports && code + code_len > exports)
126 fatal ("No export section");
128 code_len -= (exports - code);
130 if (code_len < exports_len)
131 fatal ("Corrupt exports");
133 /* Load exports section */
134 if (fseek (dll_file, get_int (buff + SECTION_POS_OFFSET)
135 + exports - code, SEEK_SET) == -1)
136 fatal ("Export section seek error");
139 printf ("Export data size = %d bytes\n", code_len);
141 if (!(buff = (char *) realloc (buff, code_len)))
142 fatal ("Out of memory");
144 if (fread (buff, code_len, 1, dll_file) != 1)
145 fatal ("Read error");
149 /* Locate symbol names/ordinals */
150 symbol_data = REBASE( get_int (buff + EXPORT_NAME_OFFSET));
151 ordinal_data = REBASE( get_int (buff + ORDINAL_NAME_OFFSET));
153 if (symbol_data > code_len)
154 fatal ("Corrupt exports section");
156 if (!(dll_num_ordinals = get_int (buff + ORDINAL_COUNT_OFFSET)))
157 fatal ("No ordinal count");
159 if (!(dll_num_exports = get_int (buff + EXPORT_COUNT_OFFSET)))
160 fatal ("No export count");
162 if (!(dll_symbols = (dll_symbol *) malloc ((dll_num_exports + 1) * sizeof (dll_symbol))))
163 fatal ("Out of memory");
165 dll_ordinal_base = get_int (buff + ORDINAL_BASE_OFFSET);
167 if (dll_num_exports != dll_num_ordinals || dll_ordinal_base > 1)
168 globals.do_ordinals = 1;
170 /* Read symbol names into 'dll_symbols' */
172 while (count < dll_num_exports)
174 const int symbol_offset = get_int (buff + symbol_data + count * 4);
175 const char *symbol_name_ptr = REBASE (buff + symbol_offset);
176 const int ordinal_offset = get_short (buff + ordinal_data + count * 2);
178 assert(symbol_name_ptr);
179 dll_symbols[count].symbol = strdup (symbol_name_ptr);
180 assert(dll_symbols[count].symbol);
181 dll_symbols[count].ordinal = ordinal_offset + dll_ordinal_base;
187 printf ("%d named symbols in DLL, %d total\n", dll_num_exports, dll_num_ordinals);
191 qsort( dll_symbols, dll_num_exports, sizeof(dll_symbol), symbol_cmp );
193 dll_symbols[dll_num_exports].symbol = NULL;
195 dll_current_symbol = dll_symbols;
196 dll_current_export = dll_ordinal_base;
198 /* Set DLL output names */
199 if ((buff = strrchr (globals.input_name, '/')))
200 globals.input_name = buff + 1; /* Strip path */
202 OUTPUT_UC_DLL_NAME = str_toupper( strdup (OUTPUT_DLL_NAME));
206 /*******************************************************************
209 * Get next exported symbol from dll
211 int dll_next_symbol (parsed_symbol * sym)
213 char ordinal_text[256];
214 if (dll_current_export > dll_num_ordinals)
217 assert (dll_symbols);
219 if (!dll_current_symbol->symbol || dll_current_export < dll_current_symbol->ordinal)
221 assert(globals.do_ordinals);
223 /* Ordinal only entry */
224 snprintf (ordinal_text, sizeof(ordinal_text), "%s_%d",
225 globals.forward_dll ? globals.forward_dll : OUTPUT_UC_DLL_NAME,
227 str_toupper(ordinal_text);
228 sym->symbol = strdup (ordinal_text);
232 sym->symbol = strdup (dll_current_symbol->symbol);
233 dll_current_symbol++;
235 sym->ordinal = dll_current_export;
236 dll_current_export++;
241 /*******************************************************************
244 * Free resources used by DLL
246 static void dll_close (void)
258 for (i = 0; i < dll_num_exports; i++)
259 if (dll_symbols [i].symbol)
260 free (dll_symbols [i].symbol);