minor fixes
[ia32rtools.git] / tools / cmpmrg_text.c
CommitLineData
7637b6cc 1/*
2 * ia32rtools
3 * (C) notaz, 2013,2014
4 *
5 * This work is licensed under the terms of 3-clause BSD license.
6 * See COPYING file in the top-level directory.
7 */
8
cfd23479 9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <linux/coff.h>
13#include <assert.h>
14#include <stdint.h>
15
ede51255 16#include "my_assert.h"
17
cfd23479 18/* http://www.delorie.com/djgpp/doc/coff/ */
19
20typedef struct {
21 unsigned short f_magic; /* magic number */
22 unsigned short f_nscns; /* number of sections */
23 unsigned int f_timdat; /* time & date stamp */
24 unsigned int f_symptr; /* file pointer to symtab */
25 unsigned int f_nsyms; /* number of symtab entries */
26 unsigned short f_opthdr; /* sizeof(optional hdr) */
27 unsigned short f_flags; /* flags */
28} FILHDR;
29
30typedef struct {
31 unsigned short magic; /* type of file */
32 unsigned short vstamp; /* version stamp */
33 unsigned int tsize; /* text size in bytes, padded to FW bdry*/
34 unsigned int dsize; /* initialized data " " */
35 unsigned int bsize; /* uninitialized data " " */
36 unsigned int entry; /* entry pt. */
37 unsigned int text_start; /* base of text used for this file */
38 unsigned int data_start; /* base of data used for this file */
39} AOUTHDR;
40
41typedef struct {
42 char s_name[8]; /* section name */
43 unsigned int s_paddr; /* physical address, aliased s_nlib */
44 unsigned int s_vaddr; /* virtual address */
45 unsigned int s_size; /* section size */
46 unsigned int s_scnptr; /* file ptr to raw data for section */
47 unsigned int s_relptr; /* file ptr to relocation */
48 unsigned int s_lnnoptr; /* file ptr to line numbers */
49 unsigned short s_nreloc; /* number of relocation entries */
50 unsigned short s_nlnno; /* number of line number entries */
51 unsigned int s_flags; /* flags */
52} SCNHDR;
53
54typedef struct {
55 unsigned int r_vaddr; /* address of relocation */
56 unsigned int r_symndx; /* symbol we're adjusting for */
57 unsigned short r_type; /* type of relocation */
58} __attribute__((packed)) RELOC;
59
e86c9ee6 60typedef struct {
61 union {
62 char e_name[E_SYMNMLEN];
63 struct {
64 unsigned int e_zeroes;
65 unsigned int e_offset;
66 } e;
67 } e;
68 unsigned int e_value;
69 short e_scnum;
70 unsigned short e_type;
71 unsigned char e_sclass;
72 unsigned char e_numaux;
73} __attribute__((packed)) SYMENT;
74
75#define C_EXT 2
76
77struct my_symtab {
78 unsigned int addr;
a2f78da4 79 //unsigned int fpos; // for patching
80 unsigned int is_text:1;
e86c9ee6 81 char *name;
82};
83
572a6bea 84struct my_sect_info {
85 long scnhdr_fofs;
86 long sect_fofs;
87 long reloc_fofs;
88 uint8_t *data;
89 long size;
90 RELOC *relocs;
91 long reloc_cnt;
92};
93
e86c9ee6 94static int symt_cmp(const void *p1_, const void *p2_)
95{
96 const struct my_symtab *p1 = p1_, *p2 = p2_;
97 return p1->addr - p2->addr;
98}
99
cfd23479 100void parse_headers(FILE *f, unsigned int *base_out,
572a6bea 101 struct my_sect_info *sect_i,
a2f78da4 102 struct my_symtab **symtab_out, long *sym_cnt,
103 struct my_symtab **raw_symtab_out, long *raw_sym_cnt)
cfd23479 104{
a2f78da4 105 struct my_symtab *symt_txt = NULL;
106 struct my_symtab *symt_all = NULL;
e86c9ee6 107 char *stringtab = NULL;
cfd23479 108 unsigned int base = 0;
e86c9ee6 109 int text_scnum = 0;
110 long filesize;
111 char symname[9];
cfd23479 112 long opthdr_pos;
113 long reloc_size;
114 FILHDR hdr;
115 AOUTHDR opthdr;
116 SCNHDR scnhdr;
e86c9ee6 117 SYMENT syment;
118 int i, s, val;
cfd23479 119 int ret;
120
e86c9ee6 121 ret = fseek(f, 0, SEEK_END);
122 my_assert(ret, 0);
123
124 filesize = ftell(f);
125
126 ret = fseek(f, 0, SEEK_SET);
127 my_assert(ret, 0);
128
cfd23479 129 ret = fread(&hdr, 1, sizeof(hdr), f);
130 my_assert(ret, sizeof(hdr));
131
132 if (hdr.f_magic == 0x5a4d) // MZ
133 {
134 ret = fseek(f, 0x3c, SEEK_SET);
135 my_assert(ret, 0);
136 ret = fread(&val, 1, sizeof(val), f);
137 my_assert(ret, sizeof(val));
138
139 ret = fseek(f, val, SEEK_SET);
140 my_assert(ret, 0);
141 ret = fread(&val, 1, sizeof(val), f);
142 my_assert(ret, sizeof(val));
143 my_assert(val, 0x4550); // PE
144
145 // should be COFF now
146 ret = fread(&hdr, 1, sizeof(hdr), f);
147 my_assert(ret, sizeof(hdr));
148 }
149
150 my_assert(hdr.f_magic, COFF_I386MAGIC);
151
152 if (hdr.f_opthdr != 0)
153 {
154 opthdr_pos = ftell(f);
155
156 if (hdr.f_opthdr < sizeof(opthdr))
157 my_assert(1, 0);
158
159 ret = fread(&opthdr, 1, sizeof(opthdr), f);
160 my_assert(ret, sizeof(opthdr));
161 my_assert(opthdr.magic, COFF_ZMAGIC);
162
2c605b97 163 //printf("text_start: %x\n", opthdr.text_start);
cfd23479 164
165 if (hdr.f_opthdr > sizeof(opthdr)) {
166 ret = fread(&base, 1, sizeof(base), f);
167 my_assert(ret, sizeof(base));
2c605b97 168 //printf("base: %x\n", base);
cfd23479 169 }
170 ret = fseek(f, opthdr_pos + hdr.f_opthdr, SEEK_SET);
171 my_assert(ret, 0);
172 }
173
e86c9ee6 174 // note: assuming first non-empty one is .text ..
cfd23479 175 for (s = 0; s < hdr.f_nscns; s++) {
572a6bea 176 sect_i->scnhdr_fofs = ftell(f);
177
cfd23479 178 ret = fread(&scnhdr, 1, sizeof(scnhdr), f);
179 my_assert(ret, sizeof(scnhdr));
180
e86c9ee6 181 if (scnhdr.s_size != 0) {
182 text_scnum = s + 1;
cfd23479 183 break;
e86c9ee6 184 }
cfd23479 185 }
572a6bea 186 my_assert(s < hdr.f_nscns, 1);
cfd23479 187
2c605b97 188#if 0
e86c9ee6 189 printf("f_nsyms: %x\n", hdr.f_nsyms);
cfd23479 190 printf("s_name: '%s'\n", scnhdr.s_name);
191 printf("s_vaddr: %x\n", scnhdr.s_vaddr);
192 printf("s_size: %x\n", scnhdr.s_size);
e86c9ee6 193 //printf("s_scnptr: %x\n", scnhdr.s_scnptr);
cfd23479 194 printf("s_nreloc: %x\n", scnhdr.s_nreloc);
195 printf("--\n");
2c605b97 196#endif
cfd23479 197
198 ret = fseek(f, scnhdr.s_scnptr, SEEK_SET);
199 my_assert(ret, 0);
200
572a6bea 201 sect_i->data = malloc(scnhdr.s_size);
202 my_assert_not(sect_i->data, NULL);
203 ret = fread(sect_i->data, 1, scnhdr.s_size, f);
cfd23479 204 my_assert(ret, scnhdr.s_size);
205
572a6bea 206 sect_i->sect_fofs = scnhdr.s_scnptr;
207 sect_i->size = scnhdr.s_size;
cfd23479 208
e86c9ee6 209 // relocs
cfd23479 210 ret = fseek(f, scnhdr.s_relptr, SEEK_SET);
211 my_assert(ret, 0);
212
572a6bea 213 reloc_size = scnhdr.s_nreloc * sizeof(sect_i->relocs[0]);
214 sect_i->relocs = malloc(reloc_size + 1);
215 my_assert_not(sect_i->relocs, NULL);
216 ret = fread(sect_i->relocs, 1, reloc_size, f);
cfd23479 217 my_assert(ret, reloc_size);
218
572a6bea 219 sect_i->reloc_cnt = scnhdr.s_nreloc;
220 sect_i->reloc_fofs = scnhdr.s_relptr;
221
222 if (base != 0 && base_out != NULL)
223 *base_out = base + scnhdr.s_vaddr;
224
225 if (symtab_out == NULL || sym_cnt == NULL)
226 return;
cfd23479 227
e86c9ee6 228 // symtab
229 if (hdr.f_nsyms != 0) {
230 symname[8] = 0;
231
a2f78da4 232 symt_txt = malloc(hdr.f_nsyms * sizeof(symt_txt[0]) + 1);
233 my_assert_not(symt_txt, NULL);
234 symt_all = malloc(hdr.f_nsyms * sizeof(symt_all[0]) + 1);
235 my_assert_not(symt_all, NULL);
e86c9ee6 236
237 ret = fseek(f, hdr.f_symptr
238 + hdr.f_nsyms * sizeof(syment), SEEK_SET);
239 my_assert(ret, 0);
240 ret = fread(&i, 1, sizeof(i), f);
241 my_assert(ret, sizeof(i));
242 my_assert((unsigned int)i < filesize, 1);
243
244 stringtab = malloc(i);
245 my_assert_not(stringtab, NULL);
246 memset(stringtab, 0, 4);
247 ret = fread(stringtab + 4, 1, i - 4, f);
248 my_assert(ret, i - 4);
249
250 ret = fseek(f, hdr.f_symptr, SEEK_SET);
251 my_assert(ret, 0);
252 }
253
254 for (i = s = 0; i < hdr.f_nsyms; i++) {
a2f78da4 255 //long pos = ftell(f);
e86c9ee6 256
257 ret = fread(&syment, 1, sizeof(syment), f);
258 my_assert(ret, sizeof(syment));
259
260 strncpy(symname, syment.e.e_name, 8);
261 //printf("%3d %2d %08x '%s'\n", syment.e_sclass,
262 // syment.e_scnum, syment.e_value, symname);
263
a2f78da4 264 symt_all[i].addr = syment.e_value;
265 //symt_all[i].fpos = pos;
e86c9ee6 266 if (syment.e.e.e_zeroes == 0)
a2f78da4 267 symt_all[i].name = stringtab + syment.e.e.e_offset;
e86c9ee6 268 else
a2f78da4 269 symt_all[i].name = strdup(symname);
270
271 symt_all[i].is_text = (syment.e_scnum == text_scnum);
272 if (symt_all[i].is_text && syment.e_sclass == C_EXT) {
273 symt_txt[s] = symt_all[i];
274 s++;
275 }
e86c9ee6 276
277 if (syment.e_numaux) {
278 ret = fseek(f, syment.e_numaux * sizeof(syment),
279 SEEK_CUR);
280 my_assert(ret, 0);
281 i += syment.e_numaux;
282 }
283 }
284
a2f78da4 285 if (symt_txt != NULL)
286 qsort(symt_txt, s, sizeof(symt_txt[0]), symt_cmp);
e86c9ee6 287
288 *sym_cnt = s;
a2f78da4 289 *symtab_out = symt_txt;
290 *raw_sym_cnt = i;
291 *raw_symtab_out = symt_all;
cfd23479 292}
293
ab66ea3d 294static int try_align(uint8_t *d_obj, uint8_t *d_exe, int maxlen)
cfd23479 295{
ab66ea3d 296 static const uint8_t aligns[8][7] = {
297 { }, // [0] not used
298 { 0x90 }, // [1] nop
299 { 0x8b, 0xff }, // mov edi, edi
300 { 0x8d, 0x49, 0x00 }, // lea ecx, [ecx]
301 { 0x8d, 0x64, 0x24, 0x00 }, // lea
302 { 0x05, 0x00, 0x00, 0x00, 0x00 }, // add eax, 0
303 { 0x8d, 0x9b, 0x00, 0x00, 0x00, 0x00 },
304 { 0x8d, 0xa4, 0x24, 0x00, 0x00, 0x00, 0x00 },
305 };
306 int j = 0;
cfd23479 307 int len;
308 int i;
309
ab66ea3d 310 // check exe for common pad/align patterns
cfd23479 311 for (i = 0; i < maxlen; i++)
312 if (d_exe[i] != 0xcc)
313 break;
314
ab66ea3d 315 while (j < 8) {
316 for (j = 1; j < 8; j++) {
317 if (maxlen - i < j) {
318 j = 8;
319 break;
320 }
321 if (memcmp(&d_exe[i], aligns[j], j) == 0) {
322 i += j;
323 break;
324 }
325 }
326 }
327 if (i == 0)
328 return 0;
329
330 // now check the obj
331 for (j = 0, len = i; len > 0; )
cfd23479 332 {
333 i = len;
334 if (i > 7)
335 i = 7;
336
ab66ea3d 337 if (memcmp(d_obj, aligns[i], i) != 0)
cfd23479 338 break;
ab66ea3d 339
340 memcpy(d_obj, d_exe, i);
341 j += i;
cfd23479 342
343 len -= i;
344 d_obj += i;
ab66ea3d 345 d_exe += i;
cfd23479 346 }
347
ab66ea3d 348 return j;
cfd23479 349}
350
351struct equiv_opcode {
352 signed char len;
353 signed char ofs;
ed6ebb48 354 unsigned short cmp_rm:1;
355 unsigned short simple:1;
cfd23479 356 uint8_t v_masm[8];
357 uint8_t v_masm_mask[8];
358 uint8_t v_msvc[8];
359 uint8_t v_msvc_mask[8];
360} equiv_ops[] = {
361 // cmp $0x11,%ax
ed6ebb48 362 { 4, -1, 0, 0,
cfd23479 363 { 0x66,0x83,0xf8,0x03 }, { 0xff,0xff,0xff,0x00 },
364 { 0x66,0x3d,0x03,0x00 }, { 0xff,0xff,0x00,0xff }, },
365 // lea -0x1(%ebx,%eax,1),%esi // op mod/rm sib offs
366 // mov, test, imm grp 1
ed6ebb48 367 { 3, -2, 1, 0,
cfd23479 368 { 0x8d,0x74,0x03 }, { 0xf0,0x07,0xc0 },
369 { 0x8d,0x74,0x18 }, { 0xf0,0x07,0xc0 }, },
370 // movzbl 0x58f24a(%eax,%ecx,1),%eax
ed6ebb48 371 { 4, -3, 1, 0,
cfd23479 372 { 0x0f,0xb6,0x84,0x08 }, { 0xff,0xff,0x07,0xc0 },
373 { 0x0f,0xb6,0x84,0x01 }, { 0xff,0xff,0x07,0xc0 }, },
374 // inc/dec
ed6ebb48 375 { 3, -2, 1, 0,
cfd23479 376 { 0xfe,0x4c,0x03 }, { 0xfe,0xff,0xc0 },
377 { 0xfe,0x4c,0x18 }, { 0xfe,0xff,0xc0 }, },
378 // cmp
ed6ebb48 379 { 3, -2, 1, 0,
cfd23479 380 { 0x38,0x0c,0x0c }, { 0xff,0xff,0xc0 },
381 { 0x38,0x0c,0x30 }, { 0xff,0xff,0xc0 }, },
382 // test %dl,%bl
ed6ebb48 383 { 2, -1, 1, 0,
cfd23479 384 { 0x84,0xd3 }, { 0xfe,0xc0 },
385 { 0x84,0xda }, { 0xfe,0xc0 }, },
386 // cmp r,r/m vs rm/r
ed6ebb48 387 { 2, 0, 1, 0,
cfd23479 388 { 0x3a,0xca }, { 0xff,0xc0 },
389 { 0x38,0xd1 }, { 0xff,0xc0 }, },
390 // rep + 66 prefix
ed6ebb48 391 { 2, 0, 0, 0,
cfd23479 392 { 0xf3,0x66 }, { 0xfe,0xff },
393 { 0x66,0xf3 }, { 0xff,0xfe }, },
394 // fadd st, st(0) vs st(0), st
ed6ebb48 395 { 2, 0, 0, 0,
cfd23479 396 { 0xd8,0xc0 }, { 0xff,0xf7 },
397 { 0xdc,0xc0 }, { 0xff,0xf7 }, },
ed6ebb48 398 // [esp] vs [esp+0]
399 { 4, -1, 0, 0,
400 { 0x00,0x04,0x24,0x90 }, { 0x00,0xc7,0xff,0xff },
401 { 0x00,0x44,0x24,0x00 }, { 0x00,0xc7,0xff,0xff }, },
402 { 5, -1, 0, 0,
403 { 0x00,0x04,0x24,0x00,0x90 }, { 0x00,0xc7,0xff,0x00,0xff },
404 { 0x00,0x44,0x24,0x00,0x00 }, { 0x00,0xc7,0xff,0xff,0x00 }, },
ab66ea3d 405 { 8, -1, 0, 0,
406 { 0x00,0x04,0x24,0x00,0x00,0x00,0x00,0x90 }, { 0x00,0xc7,0xff,0x00,0x00,0x00,0x00,0xff },
407 { 0x00,0x44,0x24,0x00,0x00,0x00,0x00,0x00 }, { 0x00,0xc7,0xff,0xff,0x00,0x00,0x00,0x00 }, },
ed6ebb48 408
409 // various align insns/fillups
410 { 2, -1, 0, 0,
411 { 0x8b,0xff }, { 0xff,0xff },
412 { 0x8b,0xc0 }, { 0xff,0xff }, },
413 { 2, 0, 0, 1,
414 { 0x00,0x00 }, { 0x00,0x00 },
415 { 0x8b,0xc0 }, { 0xff,0xff }, },
416 { 3, 0, 0, 1,
417 { 0x00,0x00,0x00 }, { 0x50,0x00,0x00 },
418 { 0x2e,0x8b,0xc0 }, { 0xff,0xff,0xff }, },
cfd23479 419
420 // broad filters (may take too much..)
421 // testb $0x4,0x1d(%esi,%eax,1)
422 // movb, push, ..
ed6ebb48 423 { 3, -2, 1, 0,
cfd23479 424 { 0xf6,0x44,0x06 }, { 0x00,0x07,0xc0 },
425 { 0xf6,0x44,0x30 }, { 0x00,0x07,0xc0 }, },
426};
427
428static int cmp_mask(uint8_t *d, uint8_t *expect, uint8_t *mask, int len)
429{
430 int i;
431
432 for (i = 0; i < len; i++)
433 if ((d[i] & mask[i]) != (expect[i] & mask[i]))
434 return 1;
435
436 return 0;
437}
438
439static int check_equiv(uint8_t *d_obj, uint8_t *d_exe, int maxlen)
440{
441 uint8_t vo, ve, vo2, ve2;
442 int i, jo, je;
443 int len, ofs;
444
445 for (i = 0; i < sizeof(equiv_ops) / sizeof(equiv_ops[0]); i++)
446 {
447 struct equiv_opcode *op = &equiv_ops[i];
448
449 len = op->len;
450 if (maxlen < len)
451 continue;
452
453 ofs = op->ofs;
454 if (cmp_mask(d_obj + ofs, op->v_masm,
455 op->v_masm_mask, len))
456 continue;
457 if (cmp_mask(d_exe + ofs, op->v_msvc,
458 op->v_msvc_mask, len))
459 continue;
460
ed6ebb48 461 if (op->simple)
462 return len + ofs;
463
cfd23479 464 jo = je = 0;
465 d_obj += ofs;
466 d_exe += ofs;
467 while (1)
468 {
469 for (; jo < len; jo++)
470 if (op->v_masm_mask[jo] != 0xff)
471 break;
472 for (; je < len; je++)
473 if (op->v_msvc_mask[je] != 0xff)
474 break;
475
476 if ((jo == len && je != len) || (jo != len && je == len)) {
421216a1 477 printf("invalid equiv_op #%td\n", op - equiv_ops);
cfd23479 478 return -1;
479 }
480 if (jo == len)
ed6ebb48 481 return len + ofs; // matched
cfd23479 482
483 // var byte
484 vo = d_obj[jo] & ~op->v_masm_mask[jo];
485 ve = d_exe[je] & ~op->v_msvc_mask[je];
486 if (op->cmp_rm && op->v_masm_mask[jo] == 0xc0) {
487 vo2 = vo >> 3;
488 vo &= 7;
489 ve2 = ve & 7;
490 ve >>= 3;
491 if (vo != ve || vo2 != ve2)
492 return -1;
493 }
494 else {
495 if (vo != ve)
496 return -1;
497 }
498
499 jo++;
500 je++;
501 }
502 }
503
504 return -1;
505}
506
572a6bea 507static void fill_int3(unsigned char *d, int len)
508{
509 while (len-- > 0) {
a2f78da4 510 if (d[0] == 0xcc && d[1] == 0xcc)
572a6bea 511 break;
512 *d++ = 0xcc;
513 }
514}
515
cfd23479 516int main(int argc, char *argv[])
517{
de50b98b 518 unsigned int base = 0, addr, end, sym, *t;
572a6bea 519 struct my_sect_info s_text_obj, s_text_exe;
a2f78da4 520 struct my_symtab *raw_syms_obj = NULL;
572a6bea 521 struct my_symtab *syms_obj = NULL;
a2f78da4 522 long sym_cnt_obj, raw_sym_cnt_obj;
cfd23479 523 FILE *f_obj, *f_exe;
572a6bea 524 SCNHDR tmphdr;
525 long sztext_cmn;
c0d9cac6 526 int do_cmp = 1;
cfd23479 527 int retval = 1;
ab66ea3d 528 int bad = 0;
cfd23479 529 int left;
c0d9cac6 530 int arg;
cfd23479 531 int ret;
532 int i;
533
c0d9cac6 534 for (arg = 1; arg < argc; arg++) {
535 if (!strcmp(argv[arg], "-n"))
536 do_cmp = 0;
537 else
538 break;
539 }
540
541 if (argc != arg + 2) {
542 printf("usage:\n%s [-n] <a_obj> <exe>\n", argv[0]);
cfd23479 543 return 1;
544 }
545
c0d9cac6 546 f_obj = fopen(argv[arg++], "r+b");
cfd23479 547 if (f_obj == NULL) {
3ebea2cf 548 fprintf(stderr, "%s: ", argv[1]);
cfd23479 549 perror("");
550 return 1;
551 }
552
c0d9cac6 553 f_exe = fopen(argv[arg++], "r");
cfd23479 554 if (f_exe == NULL) {
3ebea2cf 555 fprintf(stderr, "%s: ", argv[2]);
cfd23479 556 perror("");
557 return 1;
558 }
559
a2f78da4 560 parse_headers(f_obj, NULL, &s_text_obj, &syms_obj, &sym_cnt_obj,
561 &raw_syms_obj, &raw_sym_cnt_obj);
562 parse_headers(f_exe, &base, &s_text_exe, NULL, NULL, NULL, NULL);
cfd23479 563
572a6bea 564 sztext_cmn = s_text_obj.size;
565 if (sztext_cmn > s_text_exe.size)
566 sztext_cmn = s_text_exe.size;
cfd23479 567
568 if (sztext_cmn == 0) {
569 printf("bad .text size(s): %ld, %ld\n",
572a6bea 570 s_text_obj.size, s_text_exe.size);
cfd23479 571 return 1;
572 }
573
572a6bea 574 for (i = 0; i < s_text_obj.reloc_cnt; i++)
cfd23479 575 {
572a6bea 576 unsigned int a = s_text_obj.relocs[i].r_vaddr;
577 //printf("%04x %08x\n", s_text_obj.relocs[i].r_type, a);
cfd23479 578
572a6bea 579 switch (s_text_obj.relocs[i].r_type) {
2c605b97 580 case 0x06: // RELOC_ADDR32
581 case 0x14: // RELOC_REL32
582 // must preserve stored val,
572a6bea 583 // so trash exe so that cmp passes
584 memcpy(s_text_exe.data + a, s_text_obj.data + a, 4);
cfd23479 585 break;
586 default:
2c605b97 587 printf("unknown reloc %x @%08x/%08x\n",
572a6bea 588 s_text_obj.relocs[i].r_type, a, base + a);
cfd23479 589 return 1;
590 }
591 }
592
c0d9cac6 593 if (do_cmp)
cfd23479 594 for (i = 0; i < sztext_cmn; i++)
595 {
ab66ea3d 596 if (s_text_obj.data[i] == s_text_exe.data[i]) {
597 bad = 0;
cfd23479 598 continue;
ab66ea3d 599 }
cfd23479 600
601 left = sztext_cmn - i;
602
ab66ea3d 603 ret = try_align(s_text_obj.data + i, s_text_exe.data + i, left);
604 if (ret > 0) {
605 i += ret - 1;
606 continue;
cfd23479 607 }
608
572a6bea 609 ret = check_equiv(s_text_obj.data + i, s_text_exe.data + i, left);
cfd23479 610 if (ret >= 0) {
ed6ebb48 611 i += ret - 1;
cfd23479 612 continue;
613 }
614
572a6bea 615 printf("%x: %02x vs %02x\n", base + i,
616 s_text_obj.data[i], s_text_exe.data[i]);
ab66ea3d 617 if (bad)
618 goto out;
619
620 bad = 1;
cfd23479 621 }
622
572a6bea 623 // fill removed funcs with 'int3'
2c605b97 624 for (i = 0; i < sym_cnt_obj; i++) {
625 if (strncmp(syms_obj[i].name, "rm_", 3))
626 continue;
627
628 addr = syms_obj[i].addr;
629 end = (i < sym_cnt_obj - 1)
572a6bea 630 ? syms_obj[i + 1].addr : s_text_obj.size;
631 if (addr >= s_text_obj.size || end > s_text_obj.size) {
2c605b97 632 printf("addr OOR: %x-%x '%s'\n", addr, end,
633 syms_obj[i].name);
634 goto out;
635 }
572a6bea 636 fill_int3(s_text_obj.data + addr, end - addr);
637 }
638
639 // remove relocs
640 for (i = 0; i < s_text_obj.reloc_cnt; i++) {
641 addr = s_text_obj.relocs[i].r_vaddr;
a2f78da4 642 sym = s_text_obj.relocs[i].r_symndx;
572a6bea 643 if (addr > s_text_obj.size - 4) {
644 printf("reloc addr OOR: %x\n", addr);
645 goto out;
646 }
a2f78da4 647 if (sym >= raw_sym_cnt_obj) {
648 printf("reloc sym OOR: %d/%ld\n",
649 sym, raw_sym_cnt_obj);
650 goto out;
651 }
652#if 0
653 printf("r %08x -> %08x %s\n", base + addr,
654 raw_syms_obj[sym].addr,
655 raw_syms_obj[sym].name);
656#endif
657 t = (unsigned int *)(s_text_obj.data + addr);
658 if (t[0] == 0xcccccccc
659 || t[-1] == 0xcccccccc) { // jumptab of a func?
660 t[0] = 0xcccccccc;
572a6bea 661 memmove(&s_text_obj.relocs[i],
662 &s_text_obj.relocs[i + 1],
663 (s_text_obj.reloc_cnt - i - 1)
664 * sizeof(s_text_obj.relocs[0]));
665 i--;
666 s_text_obj.reloc_cnt--;
667 }
de50b98b 668#if 0
a2f78da4 669 // note: branches/calls already linked,
670 // so only useful for dd refs
de50b98b 671 // XXX: rm'd because of switch tables
a2f78da4 672 else if (raw_syms_obj[sym].is_text) {
de50b98b 673 unsigned int addr2 = raw_syms_obj[sym].addr;
a2f78da4 674 if (s_text_obj.data[addr2] == 0xcc) {
675 printf("warning: reloc %08x -> %08x "
676 "points to rm'd target '%s'\n",
677 base + addr, base + addr2,
678 raw_syms_obj[sym].name);
679 }
680 }
de50b98b 681#endif
2c605b97 682 }
683
572a6bea 684 // patch .text
685 ret = fseek(f_obj, s_text_obj.sect_fofs, SEEK_SET);
686 my_assert(ret, 0);
687 ret = fwrite(s_text_obj.data, 1, s_text_obj.size, f_obj);
688 my_assert(ret, s_text_obj.size);
689
690 // patch relocs
691 ret = fseek(f_obj, s_text_obj.reloc_fofs, SEEK_SET);
692 my_assert(ret, 0);
693 ret = fwrite(s_text_obj.relocs, sizeof(s_text_obj.relocs[0]),
694 s_text_obj.reloc_cnt, f_obj);
695 my_assert(ret, s_text_obj.reloc_cnt);
696
697 ret = fseek(f_obj, s_text_obj.scnhdr_fofs, SEEK_SET);
698 my_assert(ret, 0);
699 ret = fread(&tmphdr, 1, sizeof(tmphdr), f_obj);
700 my_assert(ret, sizeof(tmphdr));
701
702 tmphdr.s_nreloc = s_text_obj.reloc_cnt;
703
704 ret = fseek(f_obj, s_text_obj.scnhdr_fofs, SEEK_SET);
705 my_assert(ret, 0);
706 ret = fwrite(&tmphdr, 1, sizeof(tmphdr), f_obj);
707 my_assert(ret, sizeof(tmphdr));
2c605b97 708
709 fclose(f_obj);
710 fclose(f_exe);
711
712 retval = 0;
cfd23479 713out:
714 return retval;
715}