home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 September
/
Simtel20_Sept92.cdr
/
msdos
/
pgmutl
/
val_link.arc
/
EXECFILE.C
< prev
next >
Wrap
Text File
|
1989-02-18
|
10KB
|
240 lines
/* EXECFILE.C */
/*+-------------------------------------------------------------------------+
| |
| make_EXE_header |
| |
+-------------------------------------------------------------------------+*/
void make_EXE_header()
BeginDeclarations
bit_16 checksum;
bit_32 image_size;
lseg_ptr lseg;
#define Lseg (*lseg)
bit_32 n_uninitialized_bytes;
segment_entry_ptr seg;
#define Seg (*seg)
EndDeclarations
BeginCode
image_size = exe_header_size+highest_uninitialized_byte;
Exe_header.signature = 0x5A4D;
Exe_header.image_length_MOD_512 = Bit_16(image_size Mod 512L);
Exe_header.image_length_DIV_512 = Bit_16(image_size / 512L) + 1;
Exe_header.n_header_paragraphs = Bit_16(exe_header_size ShiftedRight 4L);
n_uninitialized_bytes = (*segment_list.last).address +
(*segment_list.last).length -
highest_uninitialized_byte;
Exe_header.min_paragraphs_above = Bit_16((n_uninitialized_bytes +
AlignmentGap(n_uninitialized_bytes, 0xFL)) ShiftedRight 4L);
Exe_header.max_paragraphs_above = CPARMAXALLOC.val;
If stack_segment_found IsTrue
Then
Exe_header.initial_SS = CanonicFrame(Largest_stack_seg.address);
Exe_header.initial_SP = Bit_16(largest_stack_seg_length +
Largest_stack_seg.address -
(Bit_32(Exe_header.initial_SS) ShiftedLeft 4L));
Else
Exe_header.initial_SS = 0;
Exe_header.initial_SP = 0;
EndIf;
Exe_header.initial_CS = initial_CS;
Exe_header.initial_IP = initial_IP;
Exe_header.offset_to_relocation_table = 0x1E;
Exe_header.always_one = 1;
/*+-------------------------------------------------------------------------+
| |
| Run a checksum on all the bytes in the soon-to-exist EXE file. |
| |
+-------------------------------------------------------------------------+*/
If exechecksum.val IsTrue
Then
checksum = word_checksum(Bit_16(exe_header_size), 0, BytePtr(exe_header));
TraverseList(segment_list, seg)
BeginTraverse
ExitIf(Seg.address NotLessThan highest_uninitialized_byte);
TraverseList(Seg.lsegs, lseg)
BeginTraverse
ExitIf(Lseg.address NotLessThan highest_uninitialized_byte);
checksum += word_checksum(Bit_16(Lseg.length),
Bit_16(Lseg.address),
Lseg.data);
EndTraverse;
EndTraverse;
Else
checksum = 0xFFFF;
EndIf;
Exe_header.checksum = Complement checksum;
file_write(BytePtr(exe_header), exe_header_size);
return;
EndCode
#undef Lseg
#undef Seg
/*+-------------------------------------------------------------------------+
| |
| write_executable_image |
| |
+-------------------------------------------------------------------------+*/
void write_executable_image()
BeginDeclarations
bit_32 data_index;
bit_32 gap;
bit_32 partial_length;
lseg_ptr lseg;
#define Lseg (*lseg)
segment_entry_ptr seg;
#define Seg (*seg)
EndDeclarations
BeginCode
exec_image_start_time = Now;
/*+-------------------------------------------------------------------------+
| |
| Validate start address. |
| |
+-------------------------------------------------------------------------+*/
If start_address_found IsTrue
Then
fixup = start_address;
initial_CS = CanonicFrame(frame());
initial_IP = Bit_16(target() - frame());
If (comfile.val IsTrue) AndIf
(initial_CS IsNotZero) AndIf
(initial_IP IsNot 0x0100)
Then /* COM file start address must be 0000:0100 */
linker_error(4, "Start address for COM file is not 0000:0100.\n");
Else
If (sysfile.val IsTrue) AndIf
(initial_CS IsNotZero) AndIf
(initial_IP IsNotZero)
Then /* SYS file start address must be 0000:0000 */
linker_error(4, "Start address for SYS file is not 0000:0000.\n");
EndIf;
EndIf;
Else /* No start address found. */
linker_error(4,"No start address.\n");
initial_CS = 0;
initial_IP = 0;
EndIf;
/*+-------------------------------------------------------------------------+
| |
| Validate stack segment. |
| |
+-------------------------------------------------------------------------+*/
If (comfile.val IsTrue) AndIf (stack_segment_found IsTrue)
Then /* COM file should not have a stack segment. */
linker_error(4, "COM file should not have a stack segment.\n");
Else
If (sysfile.val IsTrue) AndIf (stack_segment_found IsTrue)
Then /* SYS file should not have a stack segment. */
linker_error(4, "SYS file should not have a stack segment.\n");
Else
If (exefile IsTrue) AndIf (stack_segment_found IsFalse)
Then /* EXE file should have a stack segment. */
linker_error(4, "EXE file should have a stack segment.\n");
EndIf;
EndIf;
EndIf;
If pause.val IsTrue
Then
printf("About to write \"%Fs\".\n", (*exe_file_list.first).filename);
printf("Press [RETURN] key to continue.\n");
gets(CharPtr(object_file_element));
EndIf;
file_open_for_write(exe_file_list.first);
If exefile IsTrue
Then
make_EXE_header();
Else
highest_uninitialized_byte = (*segment_list.last).address +
(*segment_list.last).length;
EndIf;
/*+-------------------------------------------------------------------------+
| |
| Well, we have everything we need to write the executable image. |
| So let's do it! |
| |
+-------------------------------------------------------------------------+*/
/* We will use object_file_element as a source for the gaps caused by
the alignment of segments. We will fill the gaps with zeros. */
far_set(BytePtr(object_file_element), 0, MAX_ELEMENT_SIZE);
next_available_address = address_base;
TraverseList(segment_list, seg)
BeginTraverse
LoopIf((*Seg.lsegs.first).align Is absolute_segment);
ExitIf(Seg.address NotLessThan highest_uninitialized_byte);
TraverseList(Seg.lsegs, lseg)
BeginTraverse
ExitIf(Lseg.address NotLessThan highest_uninitialized_byte);
If Lseg.address LessThan next_available_address
Then
LoopIf((Lseg.address+Lseg.length) NotGreaterThan
next_available_address);
data_index = next_available_address - Lseg.address;
partial_length = Lseg.length - data_index;
If Seg.combine IsNot blank_common_combine
Then
file_write(Addr(Lseg.data[Bit_16(data_index)]), partial_length);
Else
write_gap(partial_length);
EndIf;
Else
gap = Lseg.address - next_available_address;
If gap IsNotZero
Then
write_gap(gap);
next_available_address += gap;
EndIf;
If (Lseg.address + Lseg.length) Exceeds highest_uninitialized_byte
Then
partial_length = (Lseg.address + Lseg.length) -
highest_uninitialized_byte;
If Seg.combine IsNot blank_common_combine
Then
file_write(Lseg.data, partial_length);
Else
write_gap(partial_length);
EndIf;
Else
If Seg.combine IsNot blank_common_combine
Then
file_write(Lseg.data, Lseg.length);
Else
write_gap(Lseg.length);
EndIf;
next_available_address += Lseg.length;
EndIf;
EndIf;
EndTraverse;
EndTraverse;
file_close_for_write();
return;
EndCode
#undef Lseg
#undef Seg
/*+-------------------------------------------------------------------------+
| |
| write_gap |
| |
+-------------------------------------------------------------------------+*/
void write_gap(bit_32 length)
BeginDeclarations
EndDeclarations
BeginCode
While length Exceeds 0
BeginWhile
If length Exceeds Bit_32(MAX_ELEMENT_SIZE)
Then
file_write(BytePtr(object_file_element), Bit_32(MAX_ELEMENT_SIZE));
length -= Bit_32(MAX_ELEMENT_SIZE);
Else
file_write(BytePtr(object_file_element), length);
length = 0L;
EndIf;
EndWhile;
return;
EndCode