Example #1
0
struct process_parameter_results process_address(struct ast_node_address* param)
{
	struct process_parameter_results result;
	struct register_mapping* registr;
	bstring btmp = NULL;
	result.v_raw = NULL;
	
	if (param->value != NULL)
		btmp = expr_representation(param->value);

	if (param->bracketed && param->added)
	{
		// This is of the form [0x1000+I].
		registr = get_register_by_name_next(param->addcmpt);

		if (registr == NULL)
		{
			// Attempt to use a label in brackets that can't be.
			fprintf(stderr, "\n");
			ahalt(ERR_NEXTED_LABEL_UNSUPPORTED, param->addcmpt);
		}
		else if (registr->value == VALUE_NEXT_UNSUPPORTED)
		{
			// Attempt to use a register in brackets that can't be.
			fprintf(stderr, "\n");
			ahalt(ERR_NEXTED_REGISTER_UNSUPPORTED, param->addcmpt);
		}

		fprintf(stderr, "[%s+%s]", btmp->data, registr->name);
		result.v = registr->value;
		result.v_extra = param->value;
		result.v_extra_used = true;
		result.v_label = NULL;
	}
	else
	{
		// This is either the form 0x1000 or [0x1000].
		if (param->bracketed)
		{
			fprintf(stderr, "[%s]", btmp->data);
			result.v = NXT;
		}
		else
		{
			fprintf(stderr, "%s", btmp->data);
			result.v = NXT_LIT;
		}

		result.v_extra = param->value;
		result.v_extra_used = true;
		result.v_label = NULL;
	}
	
	if (btmp != NULL)
		bdestroy(btmp);
	
	return result;
}
Example #2
0
void ahalt_expression_exit_handler(int code, void* data)
{
	switch (code)
	{
		case EXPR_EXIT_LABEL_NOT_FOUND:
			ahalt(ERR_LABEL_NOT_FOUND, ((bstring)data)->data);
		case EXPR_EXIT_DIVIDE_BY_ZERO:
			ahalt(ERR_EXPRESSION_DIVIDE_BY_ZERO, ((bstring)data)->data);
		default:
			ahalt(ERR_GENERIC, NULL);
	}
}
Example #3
0
uint16_t aout_get_label_address(bstring name)
{
	struct aout_byte* current = start;
	uint16_t mem_index = code_offset;
	bool found_import = false;

	while (current != NULL)
	{
		if (current->type == AOUT_TYPE_METADATA_ORIGIN)
		{
			// Adjust memory address.
			mem_index = current->opcode;
		}
		else if (current->type == AOUT_TYPE_NORMAL)
		{
			// Replace the label position.
			if (current->label == NULL)
				mem_index += 1;
			else if (strcmp(current->label, name->data) == 0)
			{
				// Return the address of this label.
				return mem_index;
			}
		}
		else if (current->type == AOUT_TYPE_METADATA_IMPORT)
		{
			// Check to see if the requested label is
			// actually imported.
			if (strcmp(current->label, name->data) == 0)
			{
				// Set a temporary variable in case we
				// define the label later (in which case we'll
				// use that instead of throwing an error).
				found_import = true;
			}
		}

		// Goto next.
		current = current->next;
	}

	// Error if we get to here.
	if (found_import)
		ahalt(ERR_EXPRESSION_NOT_PERMITTED, name->data);
	else
		ahalt(ERR_LABEL_NOT_FOUND, name->data);
	return 0;
}
Example #4
0
uint16_t treloc_init(struct aout_byte* start)
{
	struct aout_byte* current;
	uint32_t mem_index;

	// Write out the table (maximum 2000 entries).
	reloc_count = 0;
	current = start;
	mem_index = 0;
	while (current != NULL)
	{
		if (current->type != AOUT_TYPE_NORMAL)
		{
			current = current->next;
			continue;
		}
		if (current->label == NULL)
			mem_index += 1;
		if (current->label_replace != NULL)
		{
			fprintf(stderr, "RELOC [0x%04X] 0x%04X (points to %s)\n", reloc_count, mem_index, current->label_replace);
			reloc_data[reloc_count] = mem_index;
			reloc_count += 1;
			if (reloc_count == RELOC_MAXIMUM_ENTRIES)
				ahalt(ERR_RELOCATION_TABLE_TOO_LARGE, NULL);
		}
		current = current->next;
	}

	// Return how much code should be offset by.
	return RELOC_OFFSET;
}
Example #5
0
uint16_t textn_init(struct aout_byte* start)
{
	struct aout_byte* current;
	uint32_t mem_index;
	char* ext_name;

	// Write out the table (maximum 2000 entries).
	extension_count = 0;
	extension_offset = 0;
	current = start;
	mem_index = 0;

	while (current != NULL)
	{
		if (current->type == AOUT_TYPE_METADATA_EXTENSION)
		{
			ext_name = textn_verify_name(current->label);

			if (ext_name == NULL)
				ahalt(ERR_EXTENSION_UNKNOWN, current->label);

			extension_data[extension_count] = ext_name;
			printd(LEVEL_VERBOSE, "EXTENSION [0x%04X] %s\n", extension_offset, ext_name);
			extension_count += 1;
			extension_offset += strlen(ext_name) + 1;

			if (extension_count == EXTENSION_MAXIMUM_ENTRIES)
				ahalt(ERR_EXTENSION_TABLE_TOO_LARGE, NULL);
		}

		current = current->next;
	}

	// Return how much code should be offset by.
	if (extension_count > 0)
		return EXTENSION_OFFSET;
	else
		return 0;
}
Example #6
0
struct aout_byte* aout_create_opcode(uint16_t opcode, uint16_t a, uint16_t b)
{
	struct aout_byte* byte = malloc(sizeof(struct aout_byte));
	byte->type = AOUT_TYPE_NORMAL;
	byte->opcode = opcode;
	byte->a = a;
	byte->b = b;
	byte->next = NULL;
	byte->prev = NULL;
	byte->expr = NULL;
	byte->label = NULL;
	byte->raw_used = false;
	byte->raw = 0x0;
	list_init(&byte->symbols);

	if (opcode == 0 && a == 0)
		ahalt(ERR_OUTPUT_NULL, NULL);

	return byte;
}
Example #7
0
struct process_parameter_results process_register(struct ast_node_register* param)
{
	struct process_parameter_results result;
	struct register_mapping* registr;

	if (param->bracketed)
		fprintf(stderr, "[%s]", param->value);
	else
		fprintf(stderr, "%s", param->value);

	registr = get_register_by_name(param->value, param->bracketed);

	if (registr == NULL)
	{
		// Must be a label.
		result.v = 0x0;
		result.v_extra = 0x0;
		result.v_extra_used = false;
		result.v_label = param->value;
		result.v_label_bracketed = param->bracketed;
		result.v_raw = NULL;
	}
	else if (registr->value == BRACKETS_UNSUPPORTED)
	{
		// Attempt to use a register in brackets that can't be.
		fprintf(stderr, "\n");
		ahalt(ERR_BRACKETED_REGISTER_UNSUPPORTED, param->value);
	}
	else
	{
		// Must be a register.
		result.v = registr->value;
		result.v_extra = 0x0;
		result.v_extra_used = false;
		result.v_label = NULL;
		result.v_label_bracketed = false;
		result.v_raw = NULL;
	}

	return result;
}
Example #8
0
uint16_t ahalt_label_resolution_not_permitted(bstring name)
{
	ahalt(ERR_LABEL_RESOLUTION_NOT_PERMITTED, name->data);
	return 0;
}
Example #9
0
void process_line(struct ast_node_line* line)
{
	struct instruction_mapping* insttype;
	struct process_parameters_results ppresults;
	struct process_parameter_results dparam;
	struct ast_node_parameter* dcurrent;
	uint32_t dchrproc;
	uint16_t i, flimit, fchar, opos;

	// Change depending on the type of line.
	switch (line->type)
	{
		case type_keyword:
			switch (line->keyword)
			{
				case BOUNDARY:
					fprintf(stderr, ".BOUNDARY");

					// Emit safety boundary of 16 NULL words.
					for (i = 0; i < 16; i += 1)
						aout_emit(aout_create_raw(0));

					break;

				case FILL:
					fprintf(stderr, ".FILL");

					// Emit N words with value X
					flimit = expr_evaluate(line->keyword_data_expr_1, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler);
					fchar = expr_evaluate(line->keyword_data_expr_2, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler);
					for (i = 0; i < flimit; i++)
						aout_emit(aout_create_raw(fchar));

					break;

				case EXTENSION:
					fprintf(stderr, ".EXTENSION %s", line->keyword_data_string);

					// Emit extension metadata.
					aout_emit(aout_create_metadata_extension(bstr2cstr(line->keyword_data_string, '0')));

					break;

				case INCBIN:
					fprintf(stderr, ".INCBIN %s", line->keyword_data_string);

					// Emit binary include metadata.
					aout_emit(aout_create_metadata_incbin(bstr2cstr(line->keyword_data_string, '0')));

					break;

				case ORIGIN:
					opos = expr_evaluate(line->keyword_data_expr_1, &ahalt_label_resolution_not_permitted, &ahalt_expression_exit_handler);
					fprintf(stderr, ".ORIGIN 0x%04X", opos);

					// Emit origin set metadata.
					aout_emit(aout_create_metadata_origin(opos));

					break;

				case EXPORT:
					fprintf(stderr, ".EXPORT %s", line->keyword_data_string);

					// Emit export metadata.
					aout_emit(aout_create_metadata_export(bstr2cstr(line->keyword_data_string, '0')));

					break;

				case IMPORT:
					fprintf(stderr, ".IMPORT %s", line->keyword_data_string);

					// Emit export metadata.
					aout_emit(aout_create_metadata_import(bstr2cstr(line->keyword_data_string, '0')));

					break;

				default:
					fprintf(stderr, "\n");
					ahalt(ERR_UNSUPPORTED_KEYWORD, NULL);
			}

			fprintf(stderr, "\n");
			break;

		case type_instruction:

			// Check to see if this is DAT.
			if (strcmp(line->instruction->instruction, "DAT") == 0)
			{
				// Handle data.
				fprintf(stderr, "EMIT DAT");

				// Process parameters as data.
				reverse_parameters(line->instruction->parameters);
				dcurrent = line->instruction->parameters->last;

				while (dcurrent != NULL)
				{
					// Process parameter normally.
					dparam = process_parameter(dcurrent);

					// Output depending on what kind of parameter it was.
					if (dparam.v_label != NULL) // If this is a label, output something that we need to replace.
						aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(dparam.v_label)))));
					else if (dparam.v_raw != NULL) // If the raw field is not null, get each character and output it.
					{
						fprintf(stderr, " \"%s\"", dparam.v_raw->data);

						for (dchrproc = 0; dchrproc < blength(dparam.v_raw); dchrproc++)
							aout_emit(aout_create_raw(dparam.v_raw->data[dchrproc]));
					}
					else if (dparam.v_extra_used == true) // Just a single address.
						aout_emit(aout_create_expr(dparam.v_extra));
					else // Something that isn't handled by DAT.
					{
						fprintf(stderr, "\n");
						ahalt(ERR_DAT_UNSUPPORTED_PARAMETER, NULL);
					}

					dcurrent = dcurrent->prev;
				}
			}
			else
			{
				// Handle instruction.
				insttype = get_instruction_by_name(line->instruction->instruction);

				if (insttype == NULL)
					ahalt(ERR_UNKNOWN_OPCODE, line->instruction->instruction);

				fprintf(stderr, "EMIT %s", insttype->name);

				// Process parameters normally.
				ppresults = process_parameters(line->instruction->parameters);

				// Force the parameter value to be NXT if it's a label.
				if (ppresults.a_label != NULL) ppresults.a = NXT_LIT;

				if (ppresults.b_label != NULL) ppresults.b = NXT_LIT;

				if (ppresults.a_label != NULL && ppresults.a_label_bracketed) ppresults.a = NXT;

				if (ppresults.b_label != NULL && ppresults.b_label_bracketed) ppresults.b = NXT;

				// Output the initial opcode.
				if (insttype->opcode != OP_NONBASIC)
					aout_emit(aout_create_opcode(insttype->opcode, ppresults.a, ppresults.b));
				else
					aout_emit(aout_create_opcode(insttype->opcode, insttype->nbopcode, ppresults.a));

				// If the parameter is a label or requires an extra word, output them.
				if (ppresults.b_label != NULL)
					aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.b_label)))));
				else if (ppresults.b_extra_used)
					aout_emit(aout_create_expr(ppresults.b_extra));

				if (ppresults.a_label != NULL)
					aout_emit(aout_create_expr(expr_new_label(bautofree(bfromcstr(ppresults.a_label)))));
				else if (ppresults.a_extra_used)
					aout_emit(aout_create_expr(ppresults.a_extra));

			}

			fprintf(stderr, "\n");
			break;

		case type_label:
			// Handle label definition.
			fprintf(stderr, ":%s\n", line->label->name);
			aout_emit(aout_create_label(line->label->name));
			break;
	}
}
Example #10
0
struct process_parameters_results process_parameters(struct ast_node_parameters* params)
{
	struct process_parameters_results result;
	struct process_parameter_results t;
	reverse_parameters(params);
	result.raw = NULL;

	if (params->last != NULL)
	{
		t = process_parameter(params->last);

		if (t.v_raw)
		{
			fprintf(stderr, "\n");
			ahalt(ERR_GEN_UNSUPPORTED_PARAMETER, NULL);
		}

		result.a = t.v;
		result.a_extra = t.v_extra;
		result.a_extra_used = t.v_extra_used;
		result.a_label = t.v_label;
		result.a_label_bracketed = t.v_label_bracketed;

		if (params->last->prev != NULL)
		{
			t = process_parameter(params->last->prev);

			if (t.v_raw)
			{
				fprintf(stderr, "\n");
				ahalt(ERR_GEN_UNSUPPORTED_PARAMETER, NULL);
			}

			result.b = t.v;
			result.b_extra = t.v_extra;
			result.b_extra_used = t.v_extra_used;
			result.b_label = t.v_label;
			result.b_label_bracketed = t.v_label_bracketed;
		}
		else
		{
			result.b = 0x0;
			result.b_extra = 0x0;
			result.b_extra_used = false;
			result.b_label = NULL;
			result.b_label_bracketed = false;
		}
	}
	else
	{
		result.a = 0x0;
		result.a_extra = 0x0;
		result.a_extra_used = false;
		result.a_label = NULL;
		result.b_label_bracketed = false;
		result.b = 0x0;
		result.b_extra = 0x0;
		result.b_extra_used = false;
		result.b_label = NULL;
		result.b_label_bracketed = false;
	}

	return result;
}
Example #11
0
uint16_t aout_write(FILE* out, bool relocatable, bool intermediate)
{
	struct aout_byte* current_outer;
	struct aout_byte* current_inner;
	struct lprov_entry* linker_provided = NULL;
	struct lprov_entry* linker_required = NULL;
	struct lprov_entry* linker_adjustment = NULL;
	struct lprov_entry* linker_section = NULL;
	struct lprov_entry* linker_output = NULL;
	struct lprov_entry* linker_temp = NULL;
	uint32_t mem_index, out_index;
	uint16_t inst;
	BFILE* temp = NULL;
	bstring bname, ename;
	uint16_t eaddr;
	bool did_find;
	bool shown_expr_warning = false;
	bool has_output = false;

	// Initialize out our extension table.
	code_offset += textn_init(start);

	// If relocatable, initialize out our relocation table.
	if (relocatable)
		code_offset += treloc_init(start);

	// First go through and evaluate all expressions that need to be.
	current_outer = start;
	out_index = code_offset;
	while (current_outer != NULL)
	{
		if (current_outer->type == AOUT_TYPE_METADATA_ORIGIN)
		{
			// Adjust memory address.
			out_index = current_outer->opcode;
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_SECTION)
		{
			assert(current_outer->label != NULL);

			// We're exporting the current address as the beginning
			// of a section.
			if (!intermediate)
				ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

			// Check to make sure outputs haven't previously been emitted.
			if (has_output)
				ahalt(ERR_OUTPUT_BEFORE_SECTION, NULL);

			// Create linker entry.
			linker_temp = lprov_create(current_outer->label, out_index);
			linker_temp->next = linker_section;
			linker_section = linker_temp;
			printd(LEVEL_VERBOSE, "LINK SECTION %s -> 0x%04X\n", current_outer->label, out_index);
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_OUTPUT)
		{
			assert(current_outer->label != NULL);

			// We're exporting the current address as the beginning
			// of a section.
			if (!intermediate)
				ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

			// Create linker entry.
			has_output = true;
			linker_temp = lprov_create(current_outer->label, out_index);
			linker_temp->next = linker_output;
			linker_output = linker_temp;
			printd(LEVEL_VERBOSE, "LINK OUTPUT 0x%04X -> %s\n", out_index, current_outer->label);
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_EXPORT)
		{
			assert(current_outer->label != NULL);

			// We're exporting the address of this label in the
			// object table.
			if (!intermediate)
				ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

			// Resolve label position.
			ename = bfromcstr(current_outer->label);
			eaddr = aout_get_label_address(ename);
			bdestroy(ename);

			// Create linker entry.
			linker_temp = lprov_create(current_outer->label, eaddr);
			linker_temp->next = linker_provided;
			linker_provided = linker_temp;
			printd(LEVEL_VERBOSE, "LINK REPLACE %s -> 0x%04X\n", current_outer->label, eaddr);
		}
		else if (current_outer->type == AOUT_TYPE_NORMAL && current_outer->expr != NULL)
		{
			if (current_outer->expr->type != EXPR_LABEL)
			{
				// This is either just a number or a more complicated expression, so
				// evaluate it using the preprocessor expression engine.
				if ((relocatable || intermediate) && !shown_expr_warning)
				{
					printd(LEVEL_WARNING, "warning: expressions will not be adjusted at link or relocation time.\n");
					printd(LEVEL_WARNING, "		ensure labels are not used as part of expressions.\n");
					shown_expr_warning = true;
				}
				current_outer->raw_used = true;
				current_outer->raw = expr_evaluate(current_outer->expr, &aout_get_label_address, &ahalt_expression_exit_handler);
				expr_delete(current_outer->expr);
				current_outer->expr = NULL;
			}
			else
			{
				// If this is just a label, we can handle it directly (this allows
				// us to handle imported labels in intermediate code).
				current_inner = start;
				mem_index = code_offset;
				did_find = false;

				// Search for .IMPORT directives first.
				while (current_inner != NULL)
				{
					if (current_inner->type == AOUT_TYPE_METADATA_ORIGIN)
					{
						// Adjust memory address.
						mem_index = current_inner->opcode;
					}
					else if (current_inner->type == AOUT_TYPE_METADATA_IMPORT)
					{
						// An imported label (we don't need to adjust
						// memory index because the existance of this type
						// of entry doesn't affect executable size).
						if (!intermediate)
							ahalt(ERR_NOT_GENERATING_INTERMEDIATE_CODE, NULL);

						assert(current_outer->expr->data != NULL);
						if (strcmp(current_inner->label, ((bstring)current_outer->expr->data)->data) == 0)
						{
							// We don't actually know our position yet;
							// that will be handled by the linker!
							current_outer->raw = 0xFFFF;
							expr_delete(current_outer->expr);
							current_outer->expr = NULL;
							linker_temp = lprov_create(current_inner->label, out_index);
							linker_temp->next = linker_required;
							linker_required = linker_temp;
							printd(LEVEL_VERBOSE, "LINK REPLACE 0x%04X -> %s\n", out_index, current_inner->label);
							did_find = true;
							break;
						}
					}

					// Goto next.
					current_inner = current_inner->next;
				}

				// If it wasn't found in the .IMPORT directives, try searching
				// labels directly using the expression engine.
				if (!did_find)
				{
					// Replace the label position.
					current_outer->raw_used = true;
					current_outer->raw = expr_evaluate(current_outer->expr, &aout_get_label_address, &ahalt_expression_exit_handler);
					expr_delete(current_outer->expr);
					current_outer->expr = NULL;
					did_find = true;

					// We also need to add this entry to the adjustment
					// table for the linker since it also needs to adjust
					// internal label jumps in files when it concatenates
					// all of the object code together.
					linker_temp = lprov_create(NULL, out_index);
					linker_temp->next = linker_adjustment;
					linker_adjustment = linker_temp;
					printd(LEVEL_VERBOSE, "LINK ADJUST 0x%04X\n", out_index);
				}
			}
		}

		if (current_outer->type == AOUT_TYPE_NORMAL && current_outer->label == NULL)
			out_index += 1;

		current_outer = current_outer->next;
	}

	// If intermediate, we need to write out our linker table
	// as the absolute first thing in the file.
	if (intermediate)
	{
		fwrite(ldata_objfmt, 1, strlen(ldata_objfmt) + 1, out);
		objfile_save(out, linker_provided, linker_required, linker_adjustment, linker_section, linker_output);

		// Adjust the "true origin" for .ORIGIN directivies because
		// the linker table won't exist in the final result when
		// linked.
		true_origin = (uint16_t)ftell(out);
	}

	// Write out our extension table.
	textn_write(out);

	// If relocatable, write out our relocation table.
	if (relocatable)
		treloc_write(out);

	// Now write to the file.
	current_outer = start;

	while (current_outer != NULL)
	{
		if (current_outer->type == AOUT_TYPE_METADATA_ORIGIN)
		{
			// Adjust origin.
			fseek(out, true_origin + current_outer->opcode * 2 /* double because the number is in words, not bytes */, SEEK_SET);
		}
		else if (current_outer->type == AOUT_TYPE_METADATA_INCBIN)
		{
			// Include binary file.
			bname = ppfind_locate(bautofree(bfromcstr(current_outer->label)));

			if (bname == NULL)
				ahalt(ERR_UNABLE_TO_INCBIN, current_outer->label);

			temp = bfopen((const char*)(bname->data), "rb");

			if (temp == NULL)
				ahalt(ERR_UNABLE_TO_INCBIN, current_outer->label);

			// Copy binary data.
			while (!bfeof(temp))
			{
				// TODO: This could be faster if we didn't do it character
				// by character.
				fputc(bfgetc(temp), out);
			}

			// Finalize.
			bfclose(temp);
			bdestroy(bname);
		}
		else if (current_outer->type == AOUT_TYPE_NORMAL)
		{
			// Update the debugging symbol.
			dbgfmt_update_symbol_list(&current_outer->symbols, (uint16_t)((ftell(out) - true_origin) / 2));

			// Normal output.
			if (current_outer->raw_used == true)
			{
				inst = current_outer->raw;
				iwrite(&inst, out);
			}
			else if (current_outer->label == NULL)
			{
				inst = INSTRUCTION_CREATE(current_outer->opcode, current_outer->a, current_outer->b);
				iwrite(&inst, out);
			}
		}

		// Goto next in linked list.
		current_outer = current_outer->next;
	}

	fflush(out);

	return (uint16_t)((ftell(out) - true_origin) / 2);
}