static void
finish_equivalences (gfc_namespace *ns)
{
  gfc_equiv *z, *y;
  gfc_symbol *sym;
  HOST_WIDE_INT offset;
  unsigned HOST_WIDE_INT align;
  bool dummy;

  for (z = ns->equiv; z; z = z->next)
    for (y = z->eq; y; y = y->eq)
      {
        if (y->used) 
	  continue;
        sym = z->expr->symtree->n.sym;
        current_segment = get_segment_info (sym, 0);

        /* All objects directly or indirectly equivalenced with this symbol.  */
        add_equivalences (&dummy);

	/* Align the block.  */
	offset = align_segment (&align);

	/* Ensure all offsets are positive.  */
	offset -= current_segment->offset & ~(align - 1);

	apply_segment_offset (current_segment, offset);

	/* Create the decl.  */
        create_common (NULL, current_segment, true);
        break;
      }
}
Beispiel #2
0
static void
finish_equivalences (gfc_namespace *ns)
{
  gfc_equiv *z, *y;
  gfc_symbol *sym;
  gfc_common_head * c;
  HOST_WIDE_INT offset;
  unsigned HOST_WIDE_INT align;
  bool dummy;

  for (z = ns->equiv; z; z = z->next)
    for (y = z->eq; y; y = y->eq)
      {
        if (y->used) 
	  continue;
        sym = z->expr->symtree->n.sym;
        current_segment = get_segment_info (sym, 0);

        /* All objects directly or indirectly equivalenced with this
	   symbol.  */
        add_equivalences (&dummy);

	/* Align the block.  */
	offset = align_segment (&align);

	/* Ensure all offsets are positive.  */
	offset -= current_segment->offset & ~(align - 1);

	apply_segment_offset (current_segment, offset);

	/* Create the decl.  If this is a module equivalence, it has a
	   unique name, pointed to by z->module.  This is written to a
	   gfc_common_header to push create_common into using
	   build_common_decl, so that the equivalence appears as an
	   external symbol.  Otherwise, a local declaration is built using
	   build_equiv_decl.  */
	if (z->module)
	  {
	    c = gfc_get_common_head ();
	    /* We've lost the real location, so use the location of the
	       enclosing procedure.  */
	    c->where = ns->proc_name->declared_at;
	    strcpy (c->name, z->module);
	  }
	else
	  c = NULL;

        create_common (c, current_segment, true);
        break;
      }
}
Beispiel #3
0
static void
translate_common (gfc_common_head *common, gfc_symbol *var_list)
{
  gfc_symbol *sym;
  segment_info *s;
  segment_info *common_segment;
  HOST_WIDE_INT offset;
  HOST_WIDE_INT current_offset;
  unsigned HOST_WIDE_INT align;
  bool saw_equiv;

  common_segment = NULL;
  offset = 0;
  current_offset = 0;
  align = 1;
  saw_equiv = false;

  /* Add symbols to the segment.  */
  for (sym = var_list; sym; sym = sym->common_next)
    {
      current_segment = common_segment;
      s = find_segment_info (sym);

      /* Symbol has already been added via an equivalence.  Multiple
	 use associations of the same common block result in equiv_built
	 being set but no information about the symbol in the segment.  */
      if (s && sym->equiv_built)
	{
	  /* Ensure the current location is properly aligned.  */
	  align = TYPE_ALIGN_UNIT (s->field);
	  current_offset = (current_offset + align - 1) &~ (align - 1);

	  /* Verify that it ended up where we expect it.  */
	  if (s->offset != current_offset)
	    {
	      gfc_error ("Equivalence for '%s' does not match ordering of "
			 "COMMON '%s' at %L", sym->name,
			 common->name, &common->where);
	    }
	}
      else
	{
	  /* A symbol we haven't seen before.  */
	  s = current_segment = get_segment_info (sym, current_offset);

	  /* Add all objects directly or indirectly equivalenced with this
	     symbol.  */
	  add_equivalences (&saw_equiv);

	  if (current_segment->offset < 0)
	    gfc_error ("The equivalence set for '%s' cause an invalid "
		       "extension to COMMON '%s' at %L", sym->name,
		       common->name, &common->where);

	  if (gfc_option.flag_align_commons)
	    offset = align_segment (&align);

	  if (offset)
	    {
	      /* The required offset conflicts with previous alignment
		 requirements.  Insert padding immediately before this
		 segment.  */
	      if (gfc_option.warn_align_commons)
		{
		  if (strcmp (common->name, BLANK_COMMON_NAME))
		    gfc_warning ("Padding of %d bytes required before '%s' in "
				 "COMMON '%s' at %L; reorder elements or use "
				 "-fno-align-commons", (int)offset,
				 s->sym->name, common->name, &common->where);
		  else
		    gfc_warning ("Padding of %d bytes required before '%s' in "
				 "COMMON at %L; reorder elements or use "
				 "-fno-align-commons", (int)offset,
				 s->sym->name, &common->where);
		}
	    }

	  /* Apply the offset to the new segments.  */
	  apply_segment_offset (current_segment, offset);
	  current_offset += offset;

	  /* Add the new segments to the common block.  */
	  common_segment = add_segments (common_segment, current_segment);
	}

      /* The offset of the next common variable.  */
      current_offset += s->length;
    }

  if (common_segment == NULL)
    {
      gfc_error ("COMMON '%s' at %L does not exist",
		 common->name, &common->where);
      return;
    }

  if (common_segment->offset != 0 && gfc_option.warn_align_commons)
    {
      if (strcmp (common->name, BLANK_COMMON_NAME))
	gfc_warning ("COMMON '%s' at %L requires %d bytes of padding; "
		     "reorder elements or use -fno-align-commons",
		     common->name, &common->where, (int)common_segment->offset);
      else
	gfc_warning ("COMMON at %L requires %d bytes of padding; "
		     "reorder elements or use -fno-align-commons",
		     &common->where, (int)common_segment->offset);
    }

  create_common (common, common_segment, saw_equiv);
}
Beispiel #4
0
/*
 *	assemble a file and load into memory
 */
Assembly* parse_file(FILE* file) {
	Assembly* assembly;					/* assembly structure */
	int labelid;								/* new label id */
	Segment* current_segment;		/* holds current segment */
	char line[MAX_LINE];				/* holds one line */
	char* items[MAX_ARGS];			/* split line into items (split on ' ' and '\t') */
	int segment;								/* holds current segment id */
	int count, i, size;					/* loop variables */
	long long params[MAX_ARGS];	/* parsed items array */
	char sbuffer[1024];					/* 1K string buffer */
	char* sourcefile;						/* current source file */
	Label* label;
	
	/* initialize variables */
	assembly = new_assembly();
	labelid = 0;
	
	linenr = 0;
	segment = UNKNOWN;
	sourcefile = NULL;
	
	/* read a line lines (returns nr of characters read, -1 if eof) */
	while(read_line(file, line, MAX_LINE) >= 0) {
		linenr++;
		/* get rid of spaces/tabs in front of the line */
		trim_line(line);

		/* split the line on spaces/tabs */
		count = split_line(line, items);
		/* note: line == items[0] */
		
		/* check if the line was not empty */
		if (strlen(line) > 0) {
			if (strcmp(line, "code") == 0) {
				/* code segment */
				segment = CODE;
				current_segment = assembly->code;
			} else if (strcmp(line, "bss") == 0) {
				/* bss segment */
				segment = BSS;
				/* bss has no segment structure */
				/* (no point in saving uninitialized data */
				current_segment = 0;
			} else if (strcmp(line, "lit") == 0) {
				/* lit segment */
				segment = LIT;
				current_segment = assembly->lit;
			} else if (strcmp(line, "data") == 0) {
				/* data segment */
				segment = DATA;
				current_segment = assembly->data;
			} else if (strcmp(line, "export") == 0) {
				/* mark label as public */
				if (count != 2) error(linenr, "invalid number of parameters");
				label = get_label(assembly, items[1]);
				/* any exported function should be included */
				label->accessed = 1;
				label->exported = TRUE;
			} else if (strcmp(line, "import") == 0) {
				/* mark label as imported */
				if (count != 2) error(linenr, "invalid number of parameters");
				get_label(assembly, items[1])->imported = TRUE;
			} else if (segment == UNKNOWN) {
				/* all other things must be in segments */
				error(linenr, "code outside segment");
			} else if (strcmp(line, "align") == 0) {
				/* align a segment */
				if (count != 2) error(linenr, "invalid number of parameters");
				params[0] = parse_numeric(items[1]);
				if (segment == BSS) {
					/* align bss just by size */
					while(assembly->bss_size % params[0]) assembly->bss_size++;
				} else {
					align_segment(current_segment, params[0]);
				}
			}	else if (strcmp(line, "byte") == 0) {
				/* one byte of data */
				if (count != 3) error(linenr, "invalid number of parameters");
				if (segment == BSS) {
					error(linenr, "can't put initialized data in bss, use data segment instead");
				} else {
					/* parse */
					params[0] = parse_numeric(items[1]);
					params[1] = parse_numeric(items[2]);
					/* write to segment */
					MS_WriteBE(current_segment->data, params[1], (int)params[0]);
					for (i = 0; i < (int)params[0]; i++) MS_WriteBit(current_segment->mask, FALSE);
				}
			}	else if (strcmp(line, "skip") == 0) {
				/* some empty space */
				if (count != 2) error(linenr, "invalid number of parameters");
				/* parse */
				params[0] = parse_numeric(items[1]);
				if (segment == BSS) {
					/* for bss: just update the size */
					assembly->bss_size += params[0];
				} else {
					/* for other segment: write zeros */
					MS_Write(current_segment->data, 0, (int)params[0]);
					for (i = 0; i < (int)params[0]; i++) MS_WriteBit(current_segment->mask, FALSE);
				}
			} else if (strcmp(line, "address") == 0) {
				/* insert address to label here */

				/* some empty space */
				if (count != 2) error(linenr, "invalid number of parameters");
				/* write the id to the current segment */
				MS_WriteBE(current_segment->data, get_label(assembly, items[1])->id, PTR_SIZE);
				/* needs to be resolved */
				for (i = 0; i < PTR_SIZE; i++) MS_WriteBit(current_segment->mask, TRUE);
			} else if (strcmp(line, "line") == 0) {
				if (count < 2) error(linenr, "invalid number of parameters");
				if (sourcefile == NULL) error(linenr, "file directive must precede line directive");

				size = sprintf(sbuffer, "$%s:", sourcefile);
				for (i = 1; i < count; i++) {
					size += sprintf(sbuffer+size, "%s", items[i]);
					if (i == count-1) {
						sbuffer[size++] = 0;
					} else {
						sbuffer[size++] = ' ';
					}
				}
				
				/* register debug label */
				label = get_label(assembly, sbuffer);
				if (label->segment == UNKNOWN) {
					if (segment == BSS) {
						label->location = assembly->bss_size;
					} else {
						label->location = current_segment->data->size;
					}
					label->segment = segment;
				}
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_LINE;
			} else if (strcmp(line, "file") == 0) {
				if (count < 2) error(linenr, "invalid number of parameters");

				size = sprintf(sbuffer, "$");
				for (i = 1; i < count; i++) {
					size += sprintf(sbuffer+size, "%s", items[i]);
					if (i == count-1) {
						sbuffer[size++] = 0;
					} else {
						sbuffer[size++] = ' ';
					}
				}

				if (sourcefile != NULL) free(sourcefile);
				sourcefile = malloc(size-1);
				strcpy(sourcefile, sbuffer+1);
				
				/* register debug label */
				label = get_label(assembly, sbuffer);
				if (segment == BSS) {
					label->location = assembly->bss_size;
				} else {
					label->location = current_segment->data->size;
				}
				label->segment = segment;
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_FILE;
			} else if (strcmp(line, "local") == 0) {
				if (count < 3) error(linenr, "invalid number of parameters");

				size = sprintf(sbuffer, "$");
				for (i = 1; i < count; i++) {
					if (i != 2) {
						size += sprintf(sbuffer+size, "%s", items[i]);
						if (i == count-1) {
							sbuffer[size++] = 0;
						} else {
							sbuffer[size++] = ' ';
						}
					}
				}
				
				/* register debug label */
				label = get_label(assembly, sbuffer);
				label->location = parse_numeric(items[2]);				

				label->segment = UNKNOWN;
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_LOCAL;
			} else if (strcmp(line, "param") == 0) {
				if (count < 3) error(linenr, "invalid number of parameters");

				size = sprintf(sbuffer, "$");
				for (i = 1; i < count; i++) {
					if (i != 2) {
						size += sprintf(sbuffer+size, "%s", items[i]);
						if (i == count-1) {
							sbuffer[size++] = 0;
						} else {
							sbuffer[size++] = ' ';
						}
					}
				}
				
				/* register debug label */
				label = get_label(assembly, sbuffer);
				label->location = parse_numeric(items[2]);
				label->segment = UNKNOWN;
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_PARAM;
			} else if (strcmp(line, "global") == 0) {
				if (count < 2) error(linenr, "invalid number of parameters");

				size = sprintf(sbuffer, "$");
				for (i = 1; i < count; i++) {
					size += sprintf(sbuffer+size, "%s", items[i]);
					if (i == count-1) {
						sbuffer[size++] = 0;
					} else {
						sbuffer[size++] = ' ';
					}
				}
				
				/* register debug label */
				label = get_label(assembly, sbuffer);
				label->ref = get_label(assembly, items[1]);
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_GLOBAL;
			} else if (strcmp(line, "function") == 0) {
				if (count < 2) error(linenr, "invalid number of parameters");

				size = sprintf(sbuffer, "$");
				for (i = 1; i < count; i++) {
					size += sprintf(sbuffer+size, "%s", items[i]);
					if (i == count-1) {
						sbuffer[size++] = 0;
					} else {
						sbuffer[size++] = ' ';
					}
				}
				
				/* register debug label */
				label = get_label(assembly, sbuffer);
				label->ref = get_label(assembly, items[1]);
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_FUNCTION;
			} else if (strcmp(line, "label") == 0) {
				/* a label; register */
				if (count != 2) error(linenr, "invalid number of parameters");

				if (segment == BSS) {
					register_label(assembly, items[1], segment, assembly->bss_size);
				} else {
					register_label(assembly, items[1], segment, current_segment->data->size);
				}
			} else if (strcmp(line, "typedef") == 0) {
				if (count < 2) error(linenr, "invalid number of parameters");

				size = sprintf(sbuffer, "$");
				for (i = 1; i < count; i++) {
					size += sprintf(sbuffer+size, "%s", items[i]);
					if (i == count-1) {
						sbuffer[size++] = 0;
					} else {
						sbuffer[size++] = ' ';
					}
				}

				/* register debug label */
				label = get_label(assembly, sbuffer);
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_TYPEDEF;
			} else if (strcmp(line, "field") == 0) {
				if (count < 2) error(linenr, "invalid number of parameters");

				size = sprintf(sbuffer, "$");
				for (i = 1; i < count; i++) {
					if (i != 2) {
						size += sprintf(sbuffer+size, "%s", items[i]);
						if (i == count-1) {
							sbuffer[size++] = 0;
						} else {
							sbuffer[size++] = ' ';
						}
					}
				}

				/* register debug label */
				label = get_label(assembly, sbuffer);
				label->location = parse_numeric(items[2]);				

				label->segment = UNKNOWN;
				/* mark as debug function, set accessed to 1 to include it in the assembly */
				label->accessed = 1;
				label->debuginfo = LABEL_DEBUG_FIELD;
			} else {
				/* not identified; should be an instruction */
				write_instruction(assembly, items, count, current_segment);
			}
		}
	}	
	
	if (sourcefile != NULL) free(sourcefile);

	/* return the structure */
	return assembly;
}
Beispiel #5
0
/*
 *	Application entry point
 */
int main(int argc, char **argv) {
	FILE *file;										/* source and destination file handle */
	char* sourcefile;							/* source file name */
	char* targetfile;							/* destination file name */
	Assembly* assembly;						/* assembly structure */
	Label *label,*reflabel;				/* temp label structure */
	int i, labels;								/* loop integer and label counter */
	HashTableEnumeration* henum;	/* temp enumeration value */
	/* processor version id */
	int proc_version_id;
	
	/* flags */
	BOOL is_output_file, debug, is_version_id;
	/* init variables */
	sourcefile = targetfile = 0;
	is_output_file = debug = is_version_id = FALSE;
	proc_version_id = 0;
	
	/* parse the command line */
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			/* switch */
			if (strcmp(&argv[i][1], "o") == 0) {
				is_output_file = TRUE;
			} else if (strcmp(&argv[i][1], "g") == 0) {
				debug = TRUE;
			} else if (strcmp(&argv[i][1], "vid") == 0) {
				is_version_id = TRUE;
			} else {
				printf("Invalid switch %s\n", argv[i]);
				printUsage();
				exit(-1);
			}
		} else if (is_output_file) {
			/* output file name */
			if (targetfile == 0) {
				targetfile = argv[i];
				is_output_file = FALSE;
			} else {
				printf("Multiple output files given\n");
				printUsage();
				exit(-1);
			}
		} else if (is_version_id) {
			/* version id */
			if (proc_version_id == 0) {
				proc_version_id = hex2bin(argv[i]);
				is_version_id = FALSE;
			} else {
				printf("Multiple version id's given\n");
				printUsage();
				exit(-1);
			}
		} else {
			/* input file name */
			if (sourcefile == 0) {
				sourcefile = argv[i];
			} else {
				printf("Multiple source files given\n");
				printUsage();
				exit(-1);
			}
		}
		 
	}

	if (proc_version_id == 0x0000) proc_version_id = DEF_PROC_VERSION_ID;
	
	/* open the source file */
	file = fopen(sourcefile, "rb");
	if (file == 0) {
		printf("Could not open source file '%s'\n", sourcefile);
		printUsage();
		exit(EXIT_FAILURE);
	}
	/* parse file */
	assembly = parse_file(file);
	fclose(file);
	
	/*
	printLabels(assembly);
	*/
	
	/* write output */
	file = fopen(targetfile, "wb");
	if (file == 0) {
		printf("Could not open target file");
		exit(-1);
	}
	
	/* magic marker */
	fputc('S', file); fputc('O', file); fputc('B', file); fputc('J', file);
	/* make room for nr of labels (sizeof(int)) */
	for (i = 0; i < sizeof(int); i++) fputc('\0', file);

	/* start enumeration over the labels */
	henum = HT_StartEnumeration(assembly->labels);
	labels = 0;	/* label counter */

	while(label = (Label*)HT_GetNextItem(henum)) {
		/* dereference */
		reflabel = label;
		while(reflabel->ref) reflabel = reflabel->ref;
		if (reflabel != label) {
			label->location = reflabel->location;
			label->segment = reflabel->segment;
		}

		/* do not write nonaccessed imported labels */
		if (!label->imported || label->accessed) {
			/* write label to file */
			/* name length */
			fputc(strlen(label->name), file);
			/* name */
			fputs(label->name, file);
			/* imported/exported flags */
			if (label->exported) {
				fputc(1, file);
			} else if (label->imported) {
				fputc(2, file);
			} else if (label->debuginfo != 0) {
				fputc(1+(label->debuginfo<<4), file);
			} else {
				fputc(0, file);
			} 
			/* segment */
			fputc((char)label->segment, file);
			/* id */
			fwrite(&label->id, sizeof(int), 1, file);
			/* location */
			fwrite(&label->location, sizeof(int), 1, file);
			/* update counter */
			labels++;
		}
	}
	/* stop the enumeration */
	HT_StopEnumeration(henum);
	
	/* align the segments to 8, (to "finish" the bitmaps) */
	align_segment(assembly->code, 8);
	align_segment(assembly->lit, 8);
	align_segment(assembly->data, 8);
	
	/* write the binary segment data and the label masks */
	/* size */
	fwrite(&assembly->code->data->size, sizeof(int), 1, file);
	/* data */
	MS_Dump(assembly->code->data, file);
	/* mask */
	MS_Dump(assembly->code->mask, file);
	/* size */
	fwrite(&assembly->lit->data->size, sizeof(int), 1, file);
	/* data */
	MS_Dump(assembly->lit->data, file);
	/* mask */
	MS_Dump(assembly->lit->mask, file);
	/* size */
	fwrite(&assembly->data->data->size, sizeof(int), 1, file);
	/* data */
	MS_Dump(assembly->data->data, file);
	/* mask */
	MS_Dump(assembly->data->mask, file);
	/* sizeof bss segment, segment itself contains uninitialized data, doesn't
			need to be stored in assembly file */
	fwrite(&assembly->bss_size, sizeof(int), 1, file);
	/* write label count */
	fseek(file, 4, SEEK_SET);
	fwrite(&labels, sizeof(int), 1, file);
	
	/* close output file */
	fclose(file);
	return 0;
}
static void
translate_common (gfc_common_head *common, gfc_symbol *var_list)
{
  gfc_symbol *sym;
  segment_info *s;
  segment_info *common_segment;
  HOST_WIDE_INT offset;
  HOST_WIDE_INT current_offset;
  unsigned HOST_WIDE_INT align;
  unsigned HOST_WIDE_INT max_align;
  bool saw_equiv;

  common_segment = NULL;
  current_offset = 0;
  max_align = 1;
  saw_equiv = false;

  /* Add symbols to the segment.  */
  for (sym = var_list; sym; sym = sym->common_next)
    {
      if (sym->equiv_built)
	{
	  /* Symbol has already been added via an equivalence.  */
	  current_segment = common_segment;
	  s = find_segment_info (sym);

	  /* Ensure the current location is properly aligned.  */
	  align = TYPE_ALIGN_UNIT (s->field);
	  current_offset = (current_offset + align - 1) &~ (align - 1);

	  /* Verify that it ended up where we expect it.  */
	  if (s->offset != current_offset)
	    {
	      gfc_error ("Equivalence for '%s' does not match ordering of "
			 "COMMON '%s' at %L", sym->name,
			 common->name, &common->where);
	    }
	}
      else
	{
	  /* A symbol we haven't seen before.  */
	  s = current_segment = get_segment_info (sym, current_offset);

	  /* Add all objects directly or indirectly equivalenced with this
	     symbol.  */
	  add_equivalences (&saw_equiv);

	  if (current_segment->offset < 0)
	    gfc_error ("The equivalence set for '%s' cause an invalid "
		       "extension to COMMON '%s' at %L", sym->name,
		       common->name, &common->where);

	  offset = align_segment (&align);

	  if (offset & (max_align - 1))
	    {
	      /* The required offset conflicts with previous alignment
		 requirements.  Insert padding immediately before this
		 segment.  */
	      gfc_warning ("Padding of %d bytes required before '%s' in "
			   "COMMON '%s' at %L", offset, s->sym->name,
			   common->name, &common->where);
	    }
	  else
	    {
	      /* Offset the whole common block.  */
	      apply_segment_offset (common_segment, offset);
	    }

	  /* Apply the offset to the new segments.  */
	  apply_segment_offset (current_segment, offset);
	  current_offset += offset;
	  if (max_align < align)
	    max_align = align;

	  /* Add the new segments to the common block.  */
	  common_segment = add_segments (common_segment, current_segment);
	}

      /* The offset of the next common variable.  */
      current_offset += s->length;
    }

  if (common_segment->offset != 0)
    {
      gfc_warning ("COMMON '%s' at %L requires %d bytes of padding at start",
		   common->name, &common->where, common_segment->offset);
    }

  create_common (common, common_segment, saw_equiv);
}