annotate keiko/oblink.c @ 1:b5139af1a420 tip basis

Fixed permissions on compile scripts
author Mike Spivey <mike@cs.ox.ac.uk>
date Fri, 13 Oct 2017 17:27:58 +0100
parents bfdcc3820b32
children
rev   line source
mike@0 1 /*
mike@0 2 * oblink.c
mike@0 3 *
mike@0 4 * This file is part of the Oxford Oberon-2 compiler
mike@0 5 * Copyright (c) 2006--2016 J. M. Spivey
mike@0 6 * All rights reserved
mike@0 7 *
mike@0 8 * Redistribution and use in source and binary forms, with or without
mike@0 9 * modification, are permitted provided that the following conditions are met:
mike@0 10 *
mike@0 11 * 1. Redistributions of source code must retain the above copyright notice,
mike@0 12 * this list of conditions and the following disclaimer.
mike@0 13 * 2. Redistributions in binary form must reproduce the above copyright notice,
mike@0 14 * this list of conditions and the following disclaimer in the documentation
mike@0 15 * and/or other materials provided with the distribution.
mike@0 16 * 3. The name of the author may not be used to endorse or promote products
mike@0 17 * derived from this software without specific prior written permission.
mike@0 18 *
mike@0 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
mike@0 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
mike@0 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
mike@0 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
mike@0 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
mike@0 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
mike@0 25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
mike@0 26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
mike@0 27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
mike@0 28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
mike@0 29 */
mike@0 30
mike@0 31 #define EXTERN
mike@0 32 #include "oblink.h"
mike@0 33 #include "keiko.h"
mike@0 34
mike@0 35 const char *version =
mike@0 36 "Oxford Oberon-2 linker version " PACKAGE_VERSION " [build " REVID "]";
mike@0 37 const char *copyright = "Copyright (C) 1999--2012 J. M. Spivey";
mike@0 38
mike@0 39 /* The module table has one entry for each module that appears in the
mike@0 40 input files. There's another table kept by the linker itself that
mike@0 41 has one entry for each module actually selected for linking. */
mike@0 42
mike@0 43 struct _module {
mike@0 44 char *m_file; /* Name of the file */
mike@0 45 char *m_name; /* Name of the module */
mike@0 46 mybool m_lib, m_needed; /* Whether a library module, whether needed */
mike@0 47 int m_dep; /* Index of first prerequisite */
mike@0 48 int m_check; /* Checksum */
mike@0 49 };
mike@0 50
mike@0 51 static growdecl(module);
mike@0 52 #define module growbuf(module, struct _module)
mike@0 53 #define nmodules growsize(module)
mike@0 54
mike@0 55 /* The imports of module m are dep[module[m].m_dep .. module[m+1].m_dep) */
mike@0 56
mike@0 57 static growdecl(dep);
mike@0 58 #define dep growbuf(dep, int)
mike@0 59 #define ndeps growsize(dep)
mike@0 60
mike@0 61 #ifdef HAVE_GETOPT_LONG_ONLY
mike@0 62 static int nfiles;
mike@0 63 static char **file;
mike@0 64 #else
mike@0 65 static growdecl(file);
mike@0 66 #define file growbuf(file, char *)
mike@0 67 #define nfiles growsize(file)
mike@0 68 #endif
mike@0 69
mike@0 70 #define MAXLINE 1024
mike@0 71
mike@0 72 static char line[MAXLINE];
mike@0 73 static int nwords;
mike@0 74 static char *words[MAXWORDS];
mike@0 75
mike@0 76 static mybool stdlib = TRUE;
mike@0 77 static char *lscript = (char *) "lscript";
mike@0 78 static char *interp = NULL;
mike@0 79 static char *outname = (char *) "a.out";
mike@0 80 static char *libdir = NULL;
mike@0 81 static char *rtlibdir = NULL;
mike@0 82
mike@0 83 static int find_module(char *name) {
mike@0 84 for (int i = 0; i < nmodules; i++)
mike@0 85 if (strcmp(name, module[i].m_name) == 0)
mike@0 86 return i;
mike@0 87
mike@0 88 return -1;
mike@0 89 }
mike@0 90
mike@0 91 /* scan -- scan a file for MODULE and IMPORT directives */
mike@0 92 static void scan(char *name, mybool islib) {
mike@0 93 FILE *fp;
mike@0 94 int m = -1, m2, chksum;
mike@0 95
mike@0 96 err_file = must_strdup(name);
mike@0 97 fp = fopen(name, "r");
mike@0 98 if (fp == NULL) {
mike@0 99 perror(name);
mike@0 100 exit(2);
mike@0 101 }
mike@0 102
mike@0 103 while (fgets(line, MAXLINE, fp) != NULL) {
mike@0 104 nwords = split_line(line, words);
mike@0 105 if (nwords == 0) continue;
mike@0 106
mike@0 107 if (strcmp(words[0], "MODULE") == 0) {
mike@0 108 char *mname = words[1];
mike@0 109 m = find_module(mname);
mike@0 110 if (m >= 0) {
mike@0 111 if (module[m].m_lib)
mike@0 112 error("%s has the same name as a library module",
mike@0 113 words[1]);
mike@0 114 else
mike@0 115 error("%s is loaded more than once", words[1]);
mike@0 116 }
mike@0 117
mike@0 118 buf_grow(module);
mike@0 119 m = nmodules;
mike@0 120 module[m].m_file = name;
mike@0 121 module[m].m_name = must_strdup(mname);
mike@0 122 module[m].m_lib = islib;
mike@0 123 module[m].m_needed = FALSE;
mike@0 124 module[m].m_dep = ndeps;
mike@0 125 module[m].m_check = strtoul(words[2], NULL, 0);
mike@0 126 nmodules++;
mike@0 127 } else if (strcmp(words[0], "IMPORT") == 0) {
mike@0 128 if (m < 0)
mike@0 129 error("IMPORT appears before MODULE in %s", name);
mike@0 130
mike@0 131 m2 = find_module(words[1]);
mike@0 132 chksum = strtoul(words[2], NULL, 0);
mike@0 133 buf_grow(dep);
mike@0 134 if (m2 < 0)
mike@0 135 error("%s imports %s -- please load it first",
mike@0 136 module[m].m_name, words[1]);
mike@0 137 else {
mike@0 138 dep[ndeps++] = m2;
mike@0 139 if (module[m2].m_check != chksum)
mike@0 140 error("checksum of module %s does not match value"
mike@0 141 " expected by module %s",
mike@0 142 words[1], module[m].m_name);
mike@0 143 }
mike@0 144 } else if (strcmp(words[0], "ENDHDR") == 0) {
mike@0 145 break;
mike@0 146 } else {
mike@0 147 panic("*bad directive %s in file header", words[0]);
mike@0 148 }
mike@0 149 }
mike@0 150
mike@0 151 fclose(fp);
mike@0 152 }
mike@0 153
mike@0 154 static void scan_files(void) {
mike@0 155 if (stdlib) {
mike@0 156 char buf[128];
mike@0 157 sprintf(buf, "%s%s%s", libdir, DIRSEP, lscript);
mike@0 158 FILE *fp = fopen(buf, "r");
mike@0 159 if (fp == NULL) {
mike@0 160 perror(buf);
mike@0 161 exit(2);
mike@0 162 }
mike@0 163
mike@0 164 while (fgets(line, MAXLINE, fp) != NULL) {
mike@0 165 line[strlen(line)-1] = '\0';
mike@0 166 sprintf(buf, "%s%s%s", libdir, DIRSEP, line);
mike@0 167 scan(must_strdup(buf), TRUE);
mike@0 168 }
mike@0 169
mike@0 170 fclose(fp);
mike@0 171 }
mike@0 172
mike@0 173 for (int i = 0; i < nfiles; i++)
mike@0 174 scan(file[i], FALSE);
mike@0 175 }
mike@0 176
mike@0 177 /* load_needed -- load files containing needed modules */
mike@0 178 static void load_needed() {
mike@0 179 for (int i = 0; i < nmodules; i++) {
mike@0 180 if (!module[i].m_needed) continue;
mike@0 181
mike@0 182 char *name = module[i].m_file;
mike@0 183 err_file = name;
mike@0 184 FILE *fp = fopen(name, "r");
mike@0 185 if (fp == NULL) {
mike@0 186 perror(name);
mike@0 187 exit(2);
mike@0 188 }
mike@0 189
mike@0 190 while (fgets(line, MAXLINE, fp) != NULL) {
mike@0 191 nwords = split_line(line, words);
mike@0 192 if (nwords == 0) continue;
mike@0 193 put_inst(words[0], &words[1], nwords-1);
mike@0 194 }
mike@0 195
mike@0 196 fclose(fp);
mike@0 197 }
mike@0 198 }
mike@0 199
mike@0 200 /* trace_imports -- compute needed modules */
mike@0 201 static void trace_imports(void) {
mike@0 202 for (int i = nmodules-1; i >= 0; i--) {
mike@0 203 if (!module[i].m_lib || strcmp(module[i].m_name, "_Builtin") == 0)
mike@0 204 module[i].m_needed = TRUE;
mike@0 205
mike@0 206 if (module[i].m_needed)
mike@0 207 for (int j = module[i].m_dep; j < module[i+1].m_dep; j++)
mike@0 208 module[dep[j]].m_needed = TRUE;
mike@0 209 }
mike@0 210
mike@0 211 #ifdef DEBUG
mike@0 212 if (dflag) {
mike@0 213 fprintf(stderr, "Needed:");
mike@0 214 for (int i = 0; i < nmodules; i++)
mike@0 215 if (module[i].m_needed)
mike@0 216 fprintf(stderr, " %s", module[i].m_name);
mike@0 217 fprintf(stderr, "\n");
mike@0 218 }
mike@0 219 #endif
mike@0 220 }
mike@0 221
mike@0 222 /* gen_main -- generate the main program */
mike@0 223 static void gen_main(void) {
mike@0 224 char buf[128];
mike@0 225
mike@0 226 if (known("MAIN")) return;
mike@0 227
mike@0 228 err_file = (char *) "main program";
mike@0 229
mike@0 230 /* For completeness, generate a header listing all loaded modules. */
mike@0 231 gen_inst("MODULE %%Main 0 0");
mike@0 232 for (int i = 0; i < nmodules; i++) {
mike@0 233 if (strcmp(module[i].m_name, "_Builtin") == 0
mike@0 234 || !module[i].m_needed) continue;
mike@0 235 gen_inst("IMPORT %s %#x", module[i].m_name, module[i].m_check);
mike@0 236 }
mike@0 237 gen_inst("ENDHDR");
mike@0 238
mike@0 239 gen_inst("PROC MAIN 0 4 0");
mike@0 240 /* Code to call each module body */
mike@0 241 for (int i = 0; i < nmodules; i++) {
mike@0 242 if (!module[i].m_needed) continue;
mike@0 243 sprintf(buf, "%s.%%main", module[i].m_name);
mike@0 244 if (known(buf)) {
mike@0 245 gen_inst("GLOBAL %s", buf);
mike@0 246 gen_inst("CALL 0");
mike@0 247 }
mike@0 248 }
mike@0 249 gen_inst("RETURN");
mike@0 250 gen_inst("END");
mike@0 251
mike@0 252 /* Make global pointer map */
mike@0 253 gen_inst("DEFINE GCMAP");
mike@0 254 for (int i = 0; i < nmodules; i++) {
mike@0 255 if (!module[i].m_needed) continue;
mike@0 256 sprintf(buf, "%s.%%gcmap", module[i].m_name);
mike@0 257 if (known(buf)) {
mike@0 258 gen_inst("WORD GC_MAP");
mike@0 259 gen_inst("WORD %s", buf);
mike@0 260 }
mike@0 261 }
mike@0 262 gen_inst("WORD GC_END");
mike@0 263 }
mike@0 264
mike@0 265 #include <getopt.h>
mike@0 266
mike@0 267 #define SCRIPT 1
mike@0 268
mike@0 269 static struct option longopts[] = {
mike@0 270 { "script", required_argument, NULL, SCRIPT },
mike@0 271 { "nostdlib", no_argument, &stdlib, FALSE },
mike@0 272 { "pl", no_argument, &linecount, TRUE },
mike@0 273 { NULL, 0, NULL, 0 }
mike@0 274 };
mike@0 275
mike@0 276 /* get_options -- analyse arguments */
mike@0 277 static void get_options(int argc, char **argv) {
mike@0 278 for (;;) {
mike@0 279 int c = getopt_long_only(argc, argv, "dvsgCi:L:R:o:k:",
mike@0 280 longopts, NULL);
mike@0 281
mike@0 282 if (c == -1) break;
mike@0 283
mike@0 284 switch (c) {
mike@0 285 case 'd':
mike@0 286 dflag++; break;
mike@0 287 case 'v':
mike@0 288 printf("%s\n", version);
mike@0 289 exit(0);
mike@0 290 break;
mike@0 291 case 's':
mike@0 292 sflag = TRUE; break;
mike@0 293 case 'g':
mike@0 294 gflag = TRUE; break;
mike@0 295 case 'C':
mike@0 296 custom = TRUE; break;
mike@0 297 case 'i':
mike@0 298 interp = optarg; break;
mike@0 299 case 'L':
mike@0 300 libdir = optarg; break;
mike@0 301 case 'R':
mike@0 302 rtlibdir = optarg; break;
mike@0 303 case 'o':
mike@0 304 outname = optarg; break;
mike@0 305 case 'k':
mike@0 306 stack_size = atoi(optarg);
mike@0 307 if (stack_size < MIN_STACK) stack_size = MIN_STACK;
mike@0 308 break;
mike@0 309 case 0:
mike@0 310 /* Long option with flag */
mike@0 311 break;
mike@0 312 case SCRIPT:
mike@0 313 /* -script */
mike@0 314 lscript = optarg; break;
mike@0 315 case '?':
mike@0 316 /* Error has been reported by getopt */
mike@0 317 exit(2);
mike@0 318 break;
mike@0 319 default:
mike@0 320 panic("*bad option");
mike@0 321 }
mike@0 322 }
mike@0 323
mike@0 324 nfiles = argc - optind;
mike@0 325 file = &argv[optind];
mike@0 326 }
mike@0 327
mike@0 328 int main(int argc, char **argv) {
mike@0 329 progname = argv[0];
mike@0 330
mike@0 331 buf_init(module, INIT_MODS, 1, struct _module, "modules");
mike@0 332 buf_init(dep, INIT_MODS, 1, int, "dependencies");
mike@0 333
mike@0 334 stack_size = STACK_SIZE;
mike@0 335
mike@0 336 get_options(argc, argv);
mike@0 337 if (nfiles == 0) panic("no input files");
mike@0 338 if (stdlib && libdir == NULL) panic("no libdir specified");
mike@0 339 if (rtlibdir == NULL) rtlibdir = libdir;
mike@0 340
mike@0 341 #define bind(x) def_global(find_symbol(#x), ABS, x, X_SYM)
mike@0 342
mike@0 343 bind(GC_BASE); bind(GC_REPEAT); bind(GC_BLOCK);
mike@0 344 bind(GC_MAP); bind(GC_FLEX); bind(GC_END); bind(GC_POINTER);
mike@0 345 bind(E_CAST); bind(E_ASSIGN); bind(E_CASE);
mike@0 346 bind(E_WITH); bind(E_ASSERT); bind(E_RETURN);
mike@0 347 bind(E_BOUND); bind(E_NULL); bind(E_DIV);
mike@0 348 bind(E_FDIV); bind(E_STACK); bind(E_GLOB);
mike@0 349
mike@0 350 /* First pass -- check for dependencies */
mike@0 351 scan_files();
mike@0 352
mike@0 353 /* Compute needed modules */
mike@0 354 buf_grow(module);
mike@0 355 module[nmodules].m_dep = ndeps;
mike@0 356 trace_imports();
mike@0 357
mike@0 358 if (status != 0) return status;
mike@0 359
mike@0 360 /* Second pass -- link the modules that are needed */
mike@0 361 init_linker(outname, interp);
mike@0 362 load_needed();
mike@0 363 gen_main();
mike@0 364 if (rtlibdir != NULL)
mike@0 365 save_string("LIBDIR", rtlibdir);
mike@0 366 end_linking();
mike@0 367
mike@0 368 if (custom)
mike@0 369 dump_prims();
mike@0 370
mike@0 371 return status;
mike@0 372 }