| /* Tool to make gzipped second stage binary |
| |
| Copyright (C) 1996,1998 Jakub Jelinek |
| |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or |
| (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
| USA. */ |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <ctype.h> |
| #include <string.h> |
| #include <arpa/inet.h> |
| |
| FILE *f, *e; |
| unsigned char buffer[2048]; |
| unsigned char buffer2[2048]; |
| unsigned short diffs[4][2048]; |
| int ndiffs[4]; |
| unsigned int lastv[4]; |
| unsigned int curoff; |
| unsigned int prevlen; |
| unsigned int prevoff; |
| |
| #define MAX_CHANGE 65535 |
| |
| void save(FILE *out, int len, int type) |
| { |
| int i, j, k; |
| int curlen = len; |
| |
| while (len > 0) { |
| i = 2048; |
| if (len < i) i = len; |
| if (fread (buffer, 1, i, f) != i) { |
| fprintf(stderr, "read %d from arg3 type %d failed\n", i, type); |
| exit(1); |
| } |
| if (fread (buffer2, 1, i, e) != i) { |
| fprintf(stderr, "read %d from arg4 type %d failed\n", i, type); |
| exit(1); |
| } |
| for (j = 0; j < i; j++) { |
| if (buffer[j] != buffer2[j]) { |
| if (buffer2[j] == buffer[j] + 4) { |
| if (curoff + j > lastv[type] + MAX_CHANGE) { |
| if (type || !prevlen || curoff + j >= prevoff + MAX_CHANGE) |
| goto bad1; |
| k = lastv[type] + MAX_CHANGE; |
| if (k < prevoff - prevlen) |
| goto bad1; |
| if (k >= prevoff) |
| k = prevoff - 1; |
| diffs[type][ndiffs[type]] = htons(k - lastv[type]); |
| lastv[type] = k; |
| ndiffs[type]++; |
| } |
| diffs[type][ndiffs[type]] = htons(curoff + j - lastv[type]); |
| lastv[type] = curoff + j; |
| ndiffs[type]++; |
| } else if (buffer2[j] == buffer[j] + 16) { |
| if (curoff + j > lastv[type+1] + MAX_CHANGE) { |
| if (type || !prevlen || curoff + j >= prevoff + MAX_CHANGE) |
| goto bad2; |
| k = lastv[type+1] + MAX_CHANGE; |
| if (k < prevoff - prevlen) |
| goto bad2; |
| if (k >= prevoff) |
| k = prevoff - 1; |
| diffs[type+1][ndiffs[type+1]] = |
| htons(k - lastv[type+1]); |
| lastv[type+1] = k; |
| ndiffs[type+1]++; |
| } |
| diffs[type+1][ndiffs[type+1]] = |
| htons(curoff + j - lastv[type+1]); |
| lastv[type+1] = curoff + j; |
| ndiffs[type+1]++; |
| } else { |
| fprintf(stderr, "Strange, small and large images differ in something" |
| " different to R_SPARC_32 and R_SPARC_HI22\n"); |
| exit(1); |
| } |
| } |
| } |
| if (fwrite (buffer, 1, i, out) != i) { |
| fprintf(stderr, "write %d failed\n", i); |
| exit(1); |
| } |
| len -= i; |
| curoff += i; |
| } |
| prevlen = curlen; |
| prevoff = curoff; |
| return; |
| bad2: |
| type++; |
| bad1: |
| fprintf(stderr, "Distance between two changes larger than %dK %d %d %d\n", |
| MAX_CHANGE / 1024, type, curoff + j, lastv[type]); |
| exit(1); |
| } |
| |
| int main(int argc, char **argv) |
| { |
| FILE *g, *h; |
| int reloc = SMALL_RELOC; |
| int first_start, first_end, second_start, second_end; |
| int end, rodata_start, rodata_end; |
| int net = 0; |
| int i = 1; |
| char sym[256]; |
| unsigned int addr; |
| |
| if (!strcmp (argv[i], "-a")) { |
| net = 1; |
| i++; |
| } |
| |
| f = fopen(argv[i++], "r"); |
| while (fgets (buffer, 256, f)) { |
| char sym[256]; |
| unsigned int addr; |
| |
| if (sscanf(buffer, "%x %*c %s\n", &addr, sym) == 2) { |
| if (!strcmp (sym, "start")) |
| reloc = addr; |
| else if (!strcmp (sym, "main_text_start")) |
| first_start = addr - reloc; |
| else if (!strcmp (sym, "main_text_end")) |
| first_end = addr - reloc; |
| else if (!strcmp (sym, "main_data_start")) |
| second_start = addr - reloc; |
| else if (!strcmp (sym, "main_data_end")) |
| second_end = addr - reloc; |
| else if (!strcmp (sym, "main_rodata_start")) |
| rodata_start = addr - reloc; |
| else if (!strcmp (sym, "main_rodata_end")) |
| rodata_end = addr - reloc; |
| else if (!strcmp (sym, "__bss_start")) |
| end = addr - reloc; |
| } |
| } |
| fclose (f); |
| f = fopen(argv[i++], "r"); |
| e = fopen(argv[i++], "r"); |
| g = fopen(argv[i++], "w"); |
| h = fopen(argv[i++], "w"); |
| if (fread(buffer, 1, 32, f) != 32) exit(1); |
| if (fread(buffer2, 1, 32, e) != 32) exit(1); |
| if (memcmp(buffer, buffer2, 32)) { |
| fprintf(stderr, "Strange. Images for 2.5MB and 3.5MB differ in a.out header\n"); |
| exit(1); |
| } |
| |
| if (!net) { |
| memset (buffer, 0, 2048); |
| if (fwrite(buffer, 1, 2048, g) != 2048) exit(1); |
| } else { |
| if (fwrite (buffer, 1, 32, g) != 32) exit(1); |
| } |
| |
| save (g, first_start, 0); |
| save (h, first_end - first_start, 2); |
| save (g, rodata_start - first_end, 0); |
| save (h, rodata_end - rodata_start, 2); |
| save (g, second_start - rodata_end, 0); |
| save (h, second_end - second_start, 2); |
| save (g, end - second_end, 0); |
| fwrite(diffs[0], 2, ndiffs[0]+1, g); |
| fwrite(diffs[1], 2, ndiffs[1]+1, g); |
| fwrite(diffs[2], 2, ndiffs[2]+1, h); |
| fwrite(diffs[3], 2, ndiffs[3]+1, h); |
| fclose (f); |
| fclose (e); |
| fclose (g); |
| fclose (h); |
| exit (0); |
| } |