1 /*
2 Z88DK Z80 Module Assembler
3 
4 Copyright (C) Paulo Custodio, 2011-2020
5 License: The Artistic License 2.0, http://www.perlfoundation.org/artistic_license_2_0
6 Repository: https://github.com/z88dk/z88dk
7 
8 Manage the code area in memory
9 */
10 
11 #include "codearea.h"
12 #include "die.h"
13 #include "errors.h"
14 #include "fileutil.h"
15 #include "init.h"
16 #include "listfile.h"
17 #include "options.h"
18 #include "strutil.h"
19 #include "utstring.h"
20 #include "z80asm.h"
21 #include <memory.h>
22 
23 /*-----------------------------------------------------------------------------
24 *   global data
25 *----------------------------------------------------------------------------*/
26 static SectionHash 	*g_sections;
27 static Section 		*g_cur_section;
28 static Section 		*g_default_section;
29 static Section 		*g_last_section;
30 static int			 g_cur_module;
31 
32 /*-----------------------------------------------------------------------------
33 *   Initialize and Terminate module
34 *----------------------------------------------------------------------------*/
DEFINE_init_module()35 DEFINE_init_module()
36 {
37     reset_codearea();	/* init default section */
38 }
39 
DEFINE_dtor_module()40 DEFINE_dtor_module()
41 {
42 	OBJ_DELETE( g_sections );
43 	g_cur_section = g_default_section = g_last_section = NULL;
44 }
45 
46 /*-----------------------------------------------------------------------------
47 *   Named Section of code, introduced by "SECTION" keyword
48 *----------------------------------------------------------------------------*/
49 DEF_CLASS( Section );
50 DEF_CLASS_HASH( Section, false );
51 
Section_init(Section * self)52 void Section_init (Section *self)
53 {
54 	self->name = "";		/* default: empty section */
55 	self->addr	= 0;
56 	self->origin = -1;
57 	self->align = 1;
58 	self->origin_found = false;
59 	self->origin_opts = false;
60 	self->section_split = false;
61 	self->asmpc = 0;
62 	self->asmpc_phase = -1;
63 	self->opcode_size = 0;
64 
65 	self->bytes = OBJ_NEW(ByteArray);
66 	OBJ_AUTODELETE(self->bytes) = false;
67 
68 	self->reloc = OBJ_NEW(intArray);
69 	OBJ_AUTODELETE(self->reloc) = false;
70 
71 	self->module_start = OBJ_NEW(intArray);
72 	OBJ_AUTODELETE( self->module_start ) = false;
73 }
74 
Section_copy(Section * self,Section * other)75 void Section_copy (Section *self, Section *other)
76 {
77 	self->bytes = ByteArray_clone(other->bytes);
78 	self->reloc = intArray_clone(other->reloc);
79 	self->module_start = intArray_clone(other->module_start);
80 }
81 
Section_fini(Section * self)82 void Section_fini (Section *self)
83 {
84 	OBJ_DELETE(self->bytes);
85 	OBJ_DELETE(self->reloc);
86 	OBJ_DELETE(self->module_start);
87 }
88 
89 /*-----------------------------------------------------------------------------
90 *   Handle list of current sections
91 *----------------------------------------------------------------------------*/
92 
93 /*-----------------------------------------------------------------------------
94 *   init to default section ""; only called at startup
95 *----------------------------------------------------------------------------*/
reset_codearea(void)96 void reset_codearea( void )
97 {
98     init_module();
99 	SectionHash_remove_all( g_sections );
100 	g_cur_section = g_default_section = g_last_section = NULL;
101 	new_section("");
102 }
103 
104 /*-----------------------------------------------------------------------------
105 *   return size of current section
106 *----------------------------------------------------------------------------*/
get_section_size(Section * section)107 int get_section_size( Section *section )
108 {
109     init_module();
110     return ByteArray_size( section->bytes );
111 }
112 
113 /*-----------------------------------------------------------------------------
114 *   compute total size of all sections
115 *----------------------------------------------------------------------------*/
get_sections_size(void)116 int get_sections_size( void )
117 {
118 	Section *section;
119 	SectionHashElem *iter;
120 	int size;
121 
122 	size = 0;
123 	for ( section = get_first_section( &iter ) ; section != NULL ;
124 		  section = get_next_section( &iter ) )
125 	{
126 		size += get_section_size( section );
127 	}
128 	return size;
129 }
130 
131 /*-----------------------------------------------------------------------------
132 *   get section by name, creates a new section if new name;
133 *	make it the current section
134 *----------------------------------------------------------------------------*/
new_section(const char * name)135 Section *new_section( const char *name )
136 {
137 	int last_id;
138 
139 	init_module();
140 	g_cur_section = SectionHash_get( g_sections, name );
141 	if ( g_cur_section == NULL )
142 	{
143 		g_cur_section = OBJ_NEW( Section );
144 		g_cur_section->name = spool_add( name );
145 		SectionHash_set( & g_sections, name, g_cur_section );
146 
147 		/* set first and last sections */
148 		if ( g_default_section == NULL )
149 			g_default_section = g_cur_section;
150 		g_last_section = g_cur_section;
151 
152 		/* define start address of all existing modules = 0, except for default section */
153 		if ( g_default_section != NULL && *name != '\0' )
154 		{
155 			last_id = intArray_size( g_default_section->module_start ) - 1;
156 			if ( last_id >= 0 )
157 				intArray_item( g_cur_section->module_start, last_id );		/* init [0..module_id] to zero */
158 		}
159 	}
160 	return g_cur_section;
161 }
162 
163 /*-----------------------------------------------------------------------------
164 *   get/set current section
165 *----------------------------------------------------------------------------*/
get_cur_section(void)166 Section *get_cur_section( void )
167 {
168 	init_module();
169 	return g_cur_section;
170 }
171 
set_cur_section(Section * section)172 Section *set_cur_section( Section *section )
173 {
174 	init_module();
175 	return (g_cur_section = section);		/* assign and return */
176 }
177 
178 /*-----------------------------------------------------------------------------
179 *   iterate through sections
180 *	pointer to iterator may be NULL if no need to iterate
181 *----------------------------------------------------------------------------*/
get_first_section(SectionHashElem ** piter)182 Section *get_first_section( SectionHashElem **piter )
183 {
184 	SectionHashElem *iter;
185 
186 	init_module();
187 	if ( piter == NULL )
188 		piter = &iter;		/* user does not need to iterate */
189 
190 	*piter = SectionHash_first( g_sections );
191 	return (*piter == NULL) ? NULL : (Section *) (*piter)->value;
192 }
193 
get_last_section(void)194 Section *get_last_section( void )
195 {
196 	init_module();
197 	return g_last_section;
198 }
199 
get_next_section(SectionHashElem ** piter)200 Section *get_next_section(  SectionHashElem **piter )
201 {
202 	init_module();
203 	*piter = SectionHash_next( *piter );
204 	return (*piter == NULL) ? NULL : (Section *) (*piter)->value;
205 }
206 
207 /*-----------------------------------------------------------------------------
208 *   Handle current module
209 *----------------------------------------------------------------------------*/
get_last_module_id(void)210 static int get_last_module_id( void )
211 {
212 	init_module();
213 	return intArray_size( g_default_section->module_start ) - 1;
214 }
215 
get_cur_module_id(void)216 int get_cur_module_id( void )
217 {
218 	init_module();
219 	return g_cur_module;
220 }
221 
set_cur_module_id(int module_id)222 void set_cur_module_id( int module_id )
223 {
224 	init_module();
225 	xassert( module_id >= 0 );
226 	xassert( module_id <= get_last_module_id() );
227 	g_cur_module = module_id;
228 }
229 
230 /*-----------------------------------------------------------------------------
231 *   return start and end offset for given section and module ID
232 *----------------------------------------------------------------------------*/
section_module_start(Section * section,int module_id)233 static int section_module_start( Section *section, int module_id )
234 {
235 	int addr, *item;
236 	int i;
237 	int cur_size;
238 
239     init_module();
240 	cur_size = intArray_size( section->module_start );
241 	if ( cur_size > module_id )
242 		addr = *( intArray_item( section->module_start, module_id ) );
243 	else
244 	{
245 		addr = 0;
246 		for ( i = cur_size < 1 ? 0 : cur_size - 1;
247 			  i < module_id; i++ )
248 		{
249 			item = intArray_item( section->module_start, i );
250 			if ( *item < addr )
251 				*item = addr;
252 			else
253 				addr = *item;
254 		}
255 
256 		/* update address with current code index */
257 		item = intArray_item( section->module_start, module_id );
258 		xassert( get_section_size( section ) >= addr );
259 
260 		addr = *item = get_section_size( section );
261 	}
262 	return addr;
263 }
264 
section_module_size(Section * section,int module_id)265 static int section_module_size(  Section *section, int module_id )
266 {
267 	int  last_module_id = get_last_module_id();
268 	int addr, size;
269 
270 	addr = section_module_start( section, module_id );
271 	if ( module_id < last_module_id )
272 		size = section_module_start( section, module_id + 1 ) - addr;
273 	else
274 		size = get_section_size( section ) - addr;
275 
276 	return size;
277 }
278 
get_cur_module_start(void)279 int get_cur_module_start( void ) { return section_module_start( g_cur_section, g_cur_module ); }
get_cur_module_size(void)280 int get_cur_module_size(  void ) { return section_module_size(  g_cur_section, g_cur_module ); }
281 
282 /*-----------------------------------------------------------------------------
283 *   allocate the addr of each of the sections, concatenating the sections in
284 *   consecutive addresses, or starting from a new address if a section
285 *	has a defined origin. Start at the command line origin, or at 0 if negative
286 *----------------------------------------------------------------------------*/
sections_alloc_addr(void)287 void sections_alloc_addr(void)
288 {
289 	Section *section, *next_section;
290 	SectionHashElem *iter;
291 	int addr;
292 
293 	init_module();
294 
295 	/* allocate addr in sequence */
296 	addr = 0;
297 	for (section = get_first_section(&iter); section != NULL; section = next_section) {
298 		if (section->origin >= 0)		/* break in address space */
299 			addr = section->origin;
300 
301 		section->addr = addr;
302 		addr += get_section_size(section);
303 
304 		// check ALIGN of next section, extend this section if needed
305 		next_section = get_next_section(&iter);
306 		if (next_section != NULL && !(next_section->origin >= 0) && next_section->align > 1
307 			&& get_section_size(next_section) > 0) {
308 			int above = addr % next_section->align;
309 			if (above > 0) {
310 				for (int i = next_section->align - above; i > 0; i--) {
311 					*(ByteArray_push(section->bytes)) = opts.filler;
312 					addr++;
313 				}
314 			}
315 		}
316 	}
317 }
318 
319 /*-----------------------------------------------------------------------------
320 *   allocate a new module, setup module_start[] and reset ASMPC of all sections,
321 *   return new unique ID; make it the current module
322 *----------------------------------------------------------------------------*/
new_module_id(void)323 int new_module_id( void )
324 {
325 	Section *section;
326 	SectionHashElem *iter;
327 	int module_id;
328 
329 	init_module();
330 	module_id = get_last_module_id() + 1;
331 
332 	/* expand all sections this new ID */
333 	for ( section = get_first_section( &iter ) ; section != NULL ;
334 		  section = get_next_section( &iter ) )
335 	{
336 		section->asmpc = 0;
337 		section->asmpc_phase = -1;
338 		section->opcode_size = 0;
339 		(void) section_module_start( section, module_id );
340 	}
341 
342 	/* init to default section */
343 	set_cur_section( g_default_section );
344 
345 	return (g_cur_module = module_id);		/* assign and return */
346 }
347 
348 /*-----------------------------------------------------------------------------
349 *   Handle ASMPC
350 *	set_PC() defines the instruction start address
351 *	every byte added increments an offset but keeps ASMPC with start of opcode
352 *	next_PC() moves to the next opcode
353 *----------------------------------------------------------------------------*/
set_PC(int addr)354 void set_PC( int addr )
355 {
356     init_module();
357 	g_cur_section->asmpc = addr;
358 	g_cur_section->opcode_size = 0;
359 }
360 
next_PC(void)361 int next_PC( void )
362 {
363     init_module();
364 	g_cur_section->asmpc += g_cur_section->opcode_size;
365 	if (g_cur_section->asmpc_phase >= 0)
366 		g_cur_section->asmpc_phase += g_cur_section->opcode_size;
367 
368 	g_cur_section->opcode_size = 0;
369 	return g_cur_section->asmpc;
370 }
371 
get_PC(void)372 int get_PC(void)
373 {
374 	init_module();
375 	return g_cur_section->asmpc;
376 }
377 
get_phased_PC(void)378 int get_phased_PC(void)
379 {
380 	init_module();
381 	return g_cur_section->asmpc_phase;
382 }
383 
inc_PC(int num_bytes)384 static void inc_PC( int num_bytes )
385 {
386     init_module();
387     g_cur_section->opcode_size += num_bytes;
388 }
389 
390 /*-----------------------------------------------------------------------------
391 *   Check space before allocating bytes in section
392 *----------------------------------------------------------------------------*/
check_space(int addr,int num_bytes)393 static void check_space( int addr, int num_bytes )
394 {
395 	init_module();
396 	if (addr + num_bytes > MAXCODESIZE && !g_cur_section->max_codesize_issued)
397 	{
398 		error_max_codesize((long)MAXCODESIZE);
399 		g_cur_section->max_codesize_issued = true;
400 	}
401 }
402 
403 /* reserve space in bytes, increment PC if buffer expanded
404    assert only the last module can be expanded */
alloc_space(int addr,int num_bytes)405 static byte_t *alloc_space( int addr, int num_bytes )
406 {
407 	int base_addr;
408 	int old_size, new_size;
409 	byte_t *buffer;
410 
411     init_module();
412 	base_addr = get_cur_module_start();
413 	old_size  = get_cur_module_size();
414 
415 	/* cannot expand unless last module */
416 	if ( get_cur_module_id() != get_last_module_id() )
417 		xassert( addr + num_bytes <= old_size );
418 
419 	check_space( base_addr + addr, num_bytes );
420 
421 	/* reserve space */
422 	if ( num_bytes > 0 )
423 	{
424 		(void)   ByteArray_item( g_cur_section->bytes, base_addr + addr + num_bytes - 1 );
425 		buffer = ByteArray_item( g_cur_section->bytes, base_addr + addr );
426 	}
427 	else
428 		buffer = NULL;	/* no allocation */
429 
430 	/* advance PC if past end of previous buffer */
431 	new_size = get_cur_module_size();
432 	if ( new_size > old_size )
433 		inc_PC( new_size - old_size );
434 
435 	return buffer;
436 }
437 
438 /*-----------------------------------------------------------------------------
439 *   patch a value at a position, or append to the end of the code area
440 *	the patch address is relative to current module and current section
441 *	and is incremented after store
442 *----------------------------------------------------------------------------*/
patch_value(int addr,int value,int num_bytes)443 void patch_value( int addr, int value, int num_bytes )
444 {
445 	byte_t *buffer;
446 
447     init_module();
448 	buffer = alloc_space( addr, num_bytes );
449 	while ( num_bytes-- > 0 )
450 	{
451 		*buffer++ = value & 0xFF;
452 		value >>= 8;
453 	}
454 }
455 
append_value(int value,int num_bytes)456 void append_value( int value, int num_bytes )
457 {
458     init_module();
459 	patch_value(get_cur_module_size(), value, num_bytes);
460 
461 	if ( opts.list )
462 		list_append( value, num_bytes );
463 }
464 
patch_byte(int addr,byte_t byte1)465 void patch_byte( int addr, byte_t byte1 ) { patch_value( addr, byte1, 1 ); }
patch_word(int addr,int word)466 void patch_word( int addr, int  word  ) { patch_value( addr, word,  2 ); }
patch_long(int addr,long dword)467 void patch_long( int addr, long dword ) { patch_value( addr, dword, 4 ); }
468 
patch_word_be(int addr,int word)469 void patch_word_be(int addr, int  word) { patch_value(addr, ((word & 0xFF00) >> 8) | ((word & 0x00FF) << 8), 2); }
470 
append_byte(byte_t byte1)471 void append_byte( byte_t byte1 ) { append_value( byte1, 1 ); }
append_word(int word)472 void append_word( int  word )  { append_value( word,  2 ); }
append_long(long dword)473 void append_long( long dword ) { append_value( dword, 4 ); }
474 
append_word_be(int word)475 void append_word_be(int  word) { append_value(((word & 0xFF00) >> 8) | ((word & 0x00FF) << 8), 2); }
476 
append_2bytes(byte_t byte1,byte_t byte2)477 void append_2bytes( byte_t byte1, byte_t byte2 )
478 {
479 	append_value( byte1, 1 );
480 	append_value( byte2, 1 );
481 }
482 
append_defs(int num_bytes,byte_t fill)483 void append_defs(int num_bytes, byte_t fill)
484 {
485 	while (num_bytes-- > 0)
486 		append_byte(fill);
487 }
488 
489 /* advance code pointer reserving space, return address of start of buffer */
append_reserve(int num_bytes)490 byte_t *append_reserve( int num_bytes )
491 {
492     init_module();
493 	return alloc_space( get_cur_module_size(), num_bytes );
494 }
495 
496 /* append binary contents of file, whole file if num_bytes < 0 */
patch_file_contents(FILE * file,int addr,long num_bytes)497 void patch_file_contents( FILE *file, int addr, long num_bytes ) {
498 	long start_ptr;
499 	byte_t *buffer;
500 
501 	init_module();
502 
503 	/* get bin file size */
504 	if ( num_bytes < 0 )
505 	{
506 		start_ptr = ftell( file );
507 
508 		fseek( file, 0, SEEK_END );				/* file pointer to end of file */
509 		num_bytes = ftell( file ) - start_ptr;
510 
511 		fseek( file, start_ptr, SEEK_SET );		/* file pointer to original position */
512 	}
513 
514 	if ( num_bytes > 0 )
515 	{
516 		buffer = alloc_space( addr, num_bytes );
517 		xfread_bytes(buffer, num_bytes, file);
518 	}
519 }
520 
patch_from_memory(byte_t * data,int addr,long num_bytes)521 void patch_from_memory(byte_t* data, int addr, long num_bytes) {
522 	init_module();
523 
524 	if (num_bytes > 0) {
525 		byte_t *buffer = alloc_space(addr, num_bytes);
526 		memcpy(buffer, data, num_bytes);
527 	}
528 }
529 
append_file_contents(FILE * file,long num_bytes)530 void append_file_contents(FILE *file, long num_bytes)
531 {
532 	init_module();
533 	patch_file_contents(file, get_cur_module_size(), num_bytes);
534 }
535 
536 /*-----------------------------------------------------------------------------
537 *   read/write current module to an open file
538 *----------------------------------------------------------------------------*/
fwrite_module_code(FILE * file,int * p_code_size)539 bool fwrite_module_code(FILE *file, int* p_code_size)
540 {
541 	Section *section;
542 	SectionHashElem *iter;
543 	bool wrote_data = false;
544 	int code_size = 0;
545 	int addr, size;
546 
547 	init_module();
548 	for (section = get_first_section(&iter); section != NULL;
549 		section = get_next_section(&iter))
550 	{
551 		addr = section_module_start(section, g_cur_module);
552 		size = section_module_size(section, g_cur_module);
553 
554 		/* write all sections, even empty ones, to allow user to define sections list by
555 		   a sequence of SECTION statements
556 		   exception: empty section, as it is the first one anyway, if no ORG is defined */
557 		if (size > 0 || section != get_first_section(NULL) ||
558 		    section->origin >= 0 || section->align > 1)
559 		{
560 			xfwrite_dword(size, file);
561 			xfwrite_bcount_cstr(section->name, file);
562 			write_origin(file, section);
563 			xfwrite_dword(section->align, file);
564 
565 			if (size > 0)		/* ByteArray_item(bytes,0) creates item[0]!! */
566 				xfwrite_bytes((char *)ByteArray_item(section->bytes, addr), size, file);
567 
568 			code_size += size;
569 			wrote_data = true;
570 		}
571 	}
572 
573 	if (wrote_data)
574 		xfwrite_dword(-1, file);		/* end marker */
575 
576 	if (p_code_size)
577 		*p_code_size = code_size;
578 
579 	return wrote_data;
580 }
581 
582 /*-----------------------------------------------------------------------------
583 *   read/write whole code area to an open file
584 *----------------------------------------------------------------------------*/
fwrite_codearea(const char * filename,FILE ** pbinfile,FILE ** prelocfile)585 void fwrite_codearea(const char *filename, FILE **pbinfile, FILE **prelocfile)
586 {
587 	STR_DEFINE(new_name, FILENAME_MAX);
588 	Section *section;
589 	SectionHashElem *iter;
590 	int section_size;
591 	int cur_section_block_size;
592 	int cur_addr;
593 
594 	init_module();
595 
596 	cur_addr = -1;
597 	cur_section_block_size = 0;
598 	for (section = get_first_section(&iter); section != NULL;
599 		section = get_next_section(&iter))
600 	{
601 		section_size = get_section_size(section);
602 
603 		if (cur_addr < 0)
604 			cur_addr = section->addr;
605 
606 		/* bytes from this section */
607 		if (section_size > 0 || section->origin >= 0 || section->section_split)
608 		{
609 			if (section->name && *section->name)					/* only if section name not empty */
610 			{
611 				/* change current file if address changed, or option -split-bin, or section_split */
612 				if ((!opts.relocatable && opts.split_bin) ||
613 					section->section_split ||
614 					cur_addr != section->addr ||
615 					(section != get_first_section(NULL) && section->origin >= 0))
616 				{
617 					if (opts.appmake)
618 						warn_org_ignored(get_obj_filename(filename), section->name);
619 					else {
620 						Str_set(new_name, path_remove_ext(filename));	/* "test" */
621 						Str_append_char(new_name, '_');
622 						Str_append(new_name, section->name);
623 
624                         xfclose_remove_empty(*pbinfile);
625 
626 						if (opts.verbose)
627 							printf("Creating binary '%s'\n", path_canon(get_bin_filename(Str_data(new_name))));
628 
629 						*pbinfile = xfopen(get_bin_filename(Str_data(new_name)), "wb");
630 
631 						if (*prelocfile) {
632                             xfclose_remove_empty(*prelocfile);
633 							*prelocfile = xfopen(get_reloc_filename(Str_data(new_name)), "wb");
634 							cur_section_block_size = 0;
635 						}
636 
637 						cur_addr = section->addr;
638 					}
639 				}
640 			}
641 
642 			xfwrite_bytes((char *)ByteArray_item(section->bytes, 0), section_size, *pbinfile);
643 
644 			if (*prelocfile) {
645 				unsigned i;
646 				for (i = 0; i < intArray_size(section->reloc); i++) {
647 					xfwrite_word(*(intArray_item(section->reloc, i)) + cur_section_block_size, *prelocfile);
648 				}
649 			}
650 
651 			cur_section_block_size += section_size;
652 		}
653 
654 		cur_addr += section_size;
655 	}
656 
657 	STR_DELETE(new_name);
658 }
659 
660 /*-----------------------------------------------------------------------------
661 *   Assembly directives
662 *----------------------------------------------------------------------------*/
663 
664 /* define a new origin, called by the ORG directive
665 *  if origin is -1, the section is split creating a new binary file */
set_origin_directive(int origin)666 void set_origin_directive(int origin)
667 {
668 	if (CURRENTSECTION->origin_found)
669 		error_org_redefined();
670 	else
671 	{
672 		CURRENTSECTION->origin_found = true;
673 		if (origin == -1)					/* signal split section binary file */
674 			CURRENTSECTION->section_split = true;
675 		else if (origin >= 0)
676 		{
677 			if (CURRENTSECTION->origin_opts && CURRENTSECTION->origin >= 0)
678 				; /* ignore ORG, as -r from command line overrides */
679 			else
680 				CURRENTSECTION->origin = origin;
681 		}
682 		else
683 			error_int_range(origin);
684 	}
685 }
686 
687 /* define a new origin, called by the --orgin command line option */
set_origin_option(int origin)688 void set_origin_option(int origin)
689 {
690 	Section *default_section;
691 
692 	if (origin < 0 || origin > 0xFFFF)
693 		error_int_range((long)origin);
694 	else
695 	{
696 		default_section = get_first_section(NULL);
697 		default_section->origin = origin;
698 		default_section->origin_opts = true;
699 	}
700 }
701 
702 
read_origin(FILE * file,Section * section)703 void read_origin(FILE* file, Section *section) {
704 	int origin = xfread_dword(file);
705 	set_origin(origin, section);
706 }
707 
set_origin(int origin,Section * section)708 extern void set_origin(int origin, Section *section) {
709 	if (origin >= 0) {
710 		section->origin = origin;
711 		section->section_split = false;
712 	}
713 	else if (origin == -2) {
714 		section->section_split = true;
715 	}
716 	else {
717 		// ignore all other values
718 	}
719 }
720 
write_origin(FILE * file,Section * section)721 void write_origin(FILE* file, Section *section) {
722 	int origin = section->origin;
723 	if (origin < 0) {
724 		if (section->section_split)
725 			origin = -2;			/* write -2 for section split */
726 		else
727 			origin = -1;			/* write -1 for not defined */
728 	}
729 
730 	xfwrite_dword(origin, file);
731 }
732 
set_phase_directive(int address)733 void set_phase_directive(int address)
734 {
735 	if (address >= 0 && address <= 0xFFFF)
736 		CURRENTSECTION->asmpc_phase = address;
737 	else
738 		error_int_range(address);
739 }
740 
clear_phase_directive()741 void clear_phase_directive()
742 {
743 	CURRENTSECTION->asmpc_phase = -1;
744 }
745