1/* $Id: btfixupprep.c,v 1.1.1.1 2007/08/03 18:52:17 Exp $ 2 Simple utility to prepare vmlinux image for sparc. 3 Resolves all BTFIXUP uses and settings and creates 4 a special .s object to link to the image. 5 6 Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ 21 22#include <stdio.h> 23#include <string.h> 24#include <ctype.h> 25#include <errno.h> 26#include <unistd.h> 27#include <stdlib.h> 28#include <malloc.h> 29 30#define MAXSYMS 1024 31 32static char *symtab = "SYMBOL TABLE:"; 33static char *relrec = "RELOCATION RECORDS FOR ["; 34static int rellen; 35static int symlen; 36int mode; 37 38struct _btfixup; 39 40typedef struct _btfixuprel { 41 char *sect; 42 unsigned long offset; 43 struct _btfixup *f; 44 int frel; 45 struct _btfixuprel *next; 46} btfixuprel; 47 48typedef struct _btfixup { 49 int type; 50 int setinitval; 51 unsigned int initval; 52 char *initvalstr; 53 char *name; 54 btfixuprel *rel; 55} btfixup; 56 57btfixup array[MAXSYMS]; 58int last = 0; 59char buffer[1024]; 60unsigned long lastfoffset = -1; 61unsigned long lastfrelno; 62btfixup *lastf; 63 64void fatal(void) __attribute__((noreturn)); 65void fatal(void) 66{ 67 fprintf(stderr, "Malformed output from objdump\n%s\n", buffer); 68 exit(1); 69} 70 71btfixup *find(int type, char *name) 72{ 73 int i; 74 for (i = 0; i < last; i++) { 75 if (array[i].type == type && !strcmp(array[i].name, name)) 76 return array + i; 77 } 78 array[last].type = type; 79 array[last].name = strdup(name); 80 array[last].setinitval = 0; 81 if (!array[last].name) fatal(); 82 array[last].rel = NULL; 83 last++; 84 if (last >= MAXSYMS) { 85 fprintf(stderr, "Ugh. Something strange. More than %d different BTFIXUP symbols\n", MAXSYMS); 86 exit(1); 87 } 88 return array + last - 1; 89} 90 91void set_mode (char *buffer) 92{ 93 for (mode = 0;; mode++) 94 if (buffer[mode] < '0' || buffer[mode] > '9') 95 break; 96 if (mode != 8 && mode != 16) 97 fatal(); 98} 99 100 101int main(int argc,char **argv) 102{ 103 char *p, *q; 104 char *sect; 105 int i, j, k; 106 unsigned int initval; 107 int shift; 108 btfixup *f; 109 btfixuprel *r, **rr; 110 unsigned long offset; 111 char *initvalstr; 112 113 symlen = strlen(symtab); 114 while (fgets (buffer, 1024, stdin) != NULL) 115 if (!strncmp (buffer, symtab, symlen)) 116 goto main0; 117 fatal(); 118main0: 119 rellen = strlen(relrec); 120 while (fgets (buffer, 1024, stdin) != NULL) 121 if (!strncmp (buffer, relrec, rellen)) 122 goto main1; 123 fatal(); 124main1: 125 sect = malloc(strlen (buffer + rellen) + 1); 126 if (!sect) fatal(); 127 strcpy (sect, buffer + rellen); 128 p = strchr (sect, ']'); 129 if (!p) fatal(); 130 *p = 0; 131 if (fgets (buffer, 1024, stdin) == NULL) 132 fatal(); 133 while (fgets (buffer, 1024, stdin) != NULL) { 134 int nbase; 135 if (!strncmp (buffer, relrec, rellen)) 136 goto main1; 137 if (mode == 0) 138 set_mode (buffer); 139 p = strchr (buffer, '\n'); 140 if (p) *p = 0; 141 if (strlen (buffer) < 22+mode) 142 continue; 143 if (strncmp (buffer + mode, " R_SPARC_", 9)) 144 continue; 145 nbase = 27 - 8 + mode; 146 if (buffer[nbase] != '_' || buffer[nbase+1] != '_' || buffer[nbase+2] != '_') 147 continue; 148 switch (buffer[nbase+3]) { 149 case 'f': /* CALL */ 150 case 'b': /* BLACKBOX */ 151 case 's': /* SIMM13 */ 152 case 'a': /* HALF */ 153 case 'h': /* SETHI */ 154 case 'i': /* INT */ 155 break; 156 default: 157 continue; 158 } 159 p = strchr (buffer + nbase+5, '+'); 160 if (p) *p = 0; 161 shift = nbase + 5; 162 if (buffer[nbase+4] == 's' && buffer[nbase+5] == '_') { 163 shift = nbase + 6; 164 if (strcmp (sect, ".init.text")) { 165 fprintf(stderr, 166 "Wrong use of '%s' BTFIXUPSET in '%s' section.\n" 167 "BTFIXUPSET_CALL can be used only in" 168 " __init sections\n", 169 buffer + shift, sect); 170 exit(1); 171 } 172 } else if (buffer[nbase+4] != '_') 173 continue; 174 if (!strcmp (sect, ".text.exit")) 175 continue; 176 if (strcmp (sect, ".text") && 177 strcmp (sect, ".init.text") && 178 strcmp (sect, ".fixup") && 179 (strcmp (sect, "__ksymtab") || buffer[nbase+3] != 'f')) { 180 if (buffer[nbase+3] == 'f') 181 fprintf(stderr, 182 "Wrong use of '%s' in '%s' section.\n" 183 " It can be used only in .text, .init.text," 184 " .fixup and __ksymtab\n", 185 buffer + shift, sect); 186 else 187 fprintf(stderr, 188 "Wrong use of '%s' in '%s' section.\n" 189 " It can be only used in .text, .init.text," 190 " and .fixup\n", buffer + shift, sect); 191 exit(1); 192 } 193 p = strstr (buffer + shift, "__btset_"); 194 if (p && buffer[nbase+4] == 's') { 195 fprintf(stderr, "__btset_ in BTFIXUP name can only be used when defining the variable, not for setting\n%s\n", buffer); 196 exit(1); 197 } 198 initval = 0; 199 initvalstr = NULL; 200 if (p) { 201 if (p[8] != '0' || p[9] != 'x') { 202 fprintf(stderr, "Pre-initialized values can be only initialized with hexadecimal constants starting 0x\n%s\n", buffer); 203 exit(1); 204 } 205 initval = strtoul(p + 10, &q, 16); 206 if (*q || !initval) { 207 fprintf(stderr, "Pre-initialized values can be only in the form name__btset_0xXXXXXXXX where X are hex digits.\nThey cannot be name__btset_0x00000000 though. Use BTFIXUPDEF_XX instead of BTFIXUPDEF_XX_INIT then.\n%s\n", buffer); 208 exit(1); 209 } 210 initvalstr = p + 10; 211 *p = 0; 212 } 213 f = find(buffer[nbase+3], buffer + shift); 214 if (buffer[nbase+4] == 's') 215 continue; 216 switch (buffer[nbase+3]) { 217 case 'f': 218 if (initval) { 219 fprintf(stderr, "Cannot use pre-initalized fixups for calls\n%s\n", buffer); 220 exit(1); 221 } 222 if (!strcmp (sect, "__ksymtab")) { 223 if (strncmp (buffer + mode+9, "32 ", 10)) { 224 fprintf(stderr, "BTFIXUP_CALL in EXPORT_SYMBOL results in relocation other than R_SPARC_32\n\%s\n", buffer); 225 exit(1); 226 } 227 } else if (strncmp (buffer + mode+9, "WDISP30 ", 10) && 228 strncmp (buffer + mode+9, "HI22 ", 10) && 229 strncmp (buffer + mode+9, "LO10 ", 10)) { 230 fprintf(stderr, "BTFIXUP_CALL results in relocation other than R_SPARC_WDISP30, R_SPARC_HI22 or R_SPARC_LO10\n%s\n", buffer); 231 exit(1); 232 } 233 break; 234 case 'b': 235 if (initval) { 236 fprintf(stderr, "Cannot use pre-initialized fixups for blackboxes\n%s\n", buffer); 237 exit(1); 238 } 239 if (strncmp (buffer + mode+9, "HI22 ", 10)) { 240 fprintf(stderr, "BTFIXUP_BLACKBOX results in relocation other than R_SPARC_HI22\n%s\n", buffer); 241 exit(1); 242 } 243 break; 244 case 's': 245 if (initval + 0x1000 >= 0x2000) { 246 fprintf(stderr, "Wrong initializer for SIMM13. Has to be from $fffff000 to $00000fff\n%s\n", buffer); 247 exit(1); 248 } 249 if (strncmp (buffer + mode+9, "13 ", 10)) { 250 fprintf(stderr, "BTFIXUP_SIMM13 results in relocation other than R_SPARC_13\n%s\n", buffer); 251 exit(1); 252 } 253 break; 254 case 'a': 255 if (initval + 0x1000 >= 0x2000 && (initval & 0x3ff)) { 256 fprintf(stderr, "Wrong initializer for HALF.\n%s\n", buffer); 257 exit(1); 258 } 259 if (strncmp (buffer + mode+9, "13 ", 10)) { 260 fprintf(stderr, "BTFIXUP_HALF results in relocation other than R_SPARC_13\n%s\n", buffer); 261 exit(1); 262 } 263 break; 264 case 'h': 265 if (initval & 0x3ff) { 266 fprintf(stderr, "Wrong initializer for SETHI. Cannot have set low 10 bits\n%s\n", buffer); 267 exit(1); 268 } 269 if (strncmp (buffer + mode+9, "HI22 ", 10)) { 270 fprintf(stderr, "BTFIXUP_SETHI results in relocation other than R_SPARC_HI22\n%s\n", buffer); 271 exit(1); 272 } 273 break; 274 case 'i': 275 if (initval) { 276 fprintf(stderr, "Cannot use pre-initalized fixups for INT\n%s\n", buffer); 277 exit(1); 278 } 279 if (strncmp (buffer + mode+9, "HI22 ", 10) && strncmp (buffer + mode+9, "LO10 ", 10)) { 280 fprintf(stderr, "BTFIXUP_INT results in relocation other than R_SPARC_HI22 and R_SPARC_LO10\n%s\n", buffer); 281 exit(1); 282 } 283 break; 284 } 285 if (!f->setinitval) { 286 f->initval = initval; 287 if (initvalstr) { 288 f->initvalstr = strdup(initvalstr); 289 if (!f->initvalstr) fatal(); 290 } 291 f->setinitval = 1; 292 } else if (f->initval != initval) { 293 fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer\n%s\n", 294 f->name, f->initvalstr ? : "0x00000000", buffer); 295 exit(1); 296 } else if (initval && strcmp(f->initvalstr, initvalstr)) { 297 fprintf(stderr, "Btfixup %s previously used with initializer %s which doesn't match with current initializer.\n" 298 "Initializers have to match literally as well.\n%s\n", 299 f->name, f->initvalstr, buffer); 300 exit(1); 301 } 302 offset = strtoul(buffer, &q, 16); 303 if (q != buffer + mode || (!offset && (mode == 8 ? strncmp (buffer, "00000000 ", 9) : strncmp (buffer, "0000000000000000 ", 17)))) { 304 fprintf(stderr, "Malformed relocation address in\n%s\n", buffer); 305 exit(1); 306 } 307 for (k = 0, r = f->rel, rr = &f->rel; r; rr = &r->next, r = r->next, k++) 308 if (r->offset == offset && !strcmp(r->sect, sect)) { 309 fprintf(stderr, "Ugh. One address has two relocation records\n"); 310 exit(1); 311 } 312 *rr = malloc(sizeof(btfixuprel)); 313 if (!*rr) fatal(); 314 (*rr)->offset = offset; 315 (*rr)->f = NULL; 316 if (buffer[nbase+3] == 'f') { 317 lastf = f; 318 lastfoffset = offset; 319 lastfrelno = k; 320 } else if (lastfoffset + 4 == offset) { 321 (*rr)->f = lastf; 322 (*rr)->frel = lastfrelno; 323 } 324 (*rr)->sect = sect; 325 (*rr)->next = NULL; 326 } 327 printf("! Generated by btfixupprep. Do not edit.\n\n"); 328 printf("\t.section\t\".data.init\",#alloc,#write\n\t.align\t4\n\n"); 329 printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n"); 330 for (i = 0; i < last; i++) { 331 f = array + i; 332 printf("\t.global\t___%cs_%s\n", f->type, f->name); 333 if (f->type == 'f') 334 printf("___%cs_%s:\n\t.word 0x%08x,0,0,", f->type, f->name, f->type << 24); 335 else 336 printf("___%cs_%s:\n\t.word 0x%08x,0,", f->type, f->name, f->type << 24); 337 for (j = 0, r = f->rel; r != NULL; j++, r = r->next); 338 if (j) 339 printf("%d\n\t.word\t", j * 2); 340 else 341 printf("0\n"); 342 for (r = f->rel, j--; r != NULL; j--, r = r->next) { 343 if (!strcmp (r->sect, ".text")) 344 printf ("_stext+0x%08lx", r->offset); 345 else if (!strcmp (r->sect, ".init.text")) 346 printf ("__init_begin+0x%08lx", r->offset); 347 else if (!strcmp (r->sect, "__ksymtab")) 348 printf ("__start___ksymtab+0x%08lx", r->offset); 349 else if (!strcmp (r->sect, ".fixup")) 350 printf ("__start___fixup+0x%08lx", r->offset); 351 else 352 fatal(); 353 if (f->type == 'f' || !r->f) 354 printf (",0"); 355 else 356 printf (",___fs_%s+0x%08x", r->f->name, (4 + r->frel*2)*4 + 4); 357 if (j) printf (","); 358 else printf ("\n"); 359 } 360 printf("\n"); 361 } 362 printf("\n\t.global\t___btfixup_end\n___btfixup_end:\n"); 363 printf("\n\n! Define undefined references\n\n"); 364 for (i = 0; i < last; i++) { 365 f = array + i; 366 if (f->type == 'f') { 367 printf("\t.global\t___f_%s\n", f->name); 368 printf("___f_%s:\n", f->name); 369 } 370 } 371 printf("\tretl\n\t nop\n\n"); 372 for (i = 0; i < last; i++) { 373 f = array + i; 374 if (f->type != 'f') { 375 if (!f->initval) { 376 printf("\t.global\t___%c_%s\n", f->type, f->name); 377 printf("___%c_%s = 0\n", f->type, f->name); 378 } else { 379 printf("\t.global\t___%c_%s__btset_0x%s\n", f->type, f->name, f->initvalstr); 380 printf("___%c_%s__btset_0x%s = 0x%08x\n", f->type, f->name, f->initvalstr, f->initval); 381 } 382 } 383 } 384 printf("\n\n"); 385 exit(0); 386} 387