home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast2.iso / pgmutil / val_link.zip / EXECFILE.C < prev    next >
Text File  |  1989-02-18  |  10KB  |  240 lines

  1. /*                                EXECFILE.C                               */
  2.  
  3. /*+-------------------------------------------------------------------------+
  4.   |                                                                         |
  5.   |                             make_EXE_header                             |
  6.   |                                                                         |
  7.   +-------------------------------------------------------------------------+*/
  8. void make_EXE_header()
  9. BeginDeclarations
  10. bit_16                                 checksum;
  11. bit_32                                 image_size;
  12. lseg_ptr                               lseg;
  13. #define Lseg                           (*lseg)
  14. bit_32                                 n_uninitialized_bytes;
  15. segment_entry_ptr                      seg;
  16. #define Seg                            (*seg)
  17. EndDeclarations
  18. BeginCode
  19.  image_size                      = exe_header_size+highest_uninitialized_byte;
  20.  Exe_header.signature            = 0x5A4D;
  21.  Exe_header.image_length_MOD_512 = Bit_16(image_size Mod 512L);
  22.  Exe_header.image_length_DIV_512 = Bit_16(image_size / 512L) + 1;
  23.  Exe_header.n_header_paragraphs  = Bit_16(exe_header_size ShiftedRight 4L);
  24.  n_uninitialized_bytes           = (*segment_list.last).address + 
  25.                                    (*segment_list.last).length - 
  26.                                    highest_uninitialized_byte;
  27.  Exe_header.min_paragraphs_above = Bit_16((n_uninitialized_bytes + 
  28.                   AlignmentGap(n_uninitialized_bytes, 0xFL)) ShiftedRight 4L);
  29.  Exe_header.max_paragraphs_above = CPARMAXALLOC.val;
  30.  If stack_segment_found IsTrue
  31.   Then
  32.    Exe_header.initial_SS = CanonicFrame(Largest_stack_seg.address);
  33.    Exe_header.initial_SP = Bit_16(largest_stack_seg_length +
  34.                            Largest_stack_seg.address -
  35.                             (Bit_32(Exe_header.initial_SS) ShiftedLeft 4L));
  36.   Else
  37.    Exe_header.initial_SS = 0;
  38.    Exe_header.initial_SP = 0;
  39.   EndIf;
  40.  Exe_header.initial_CS                 = initial_CS;
  41.  Exe_header.initial_IP                 = initial_IP;
  42.  Exe_header.offset_to_relocation_table = 0x1E;
  43.  Exe_header.always_one                 = 1;
  44. /*+-------------------------------------------------------------------------+
  45.   |                                                                         |
  46.   |    Run a checksum on all the bytes in the soon-to-exist EXE file.       |
  47.   |                                                                         |
  48.   +-------------------------------------------------------------------------+*/
  49.  If exechecksum.val IsTrue
  50.   Then
  51.    checksum = word_checksum(Bit_16(exe_header_size), 0, BytePtr(exe_header));
  52.    TraverseList(segment_list, seg)
  53.     BeginTraverse
  54.      ExitIf(Seg.address NotLessThan highest_uninitialized_byte);
  55.      TraverseList(Seg.lsegs, lseg)
  56.       BeginTraverse
  57.        ExitIf(Lseg.address NotLessThan highest_uninitialized_byte);
  58.        checksum += word_checksum(Bit_16(Lseg.length), 
  59.                                  Bit_16(Lseg.address),
  60.                                  Lseg.data);
  61.       EndTraverse;
  62.     EndTraverse;
  63.   Else
  64.    checksum = 0xFFFF;
  65.   EndIf;
  66.  Exe_header.checksum = Complement checksum;
  67.  file_write(BytePtr(exe_header), exe_header_size);
  68.  return;
  69. EndCode
  70. #undef Lseg
  71. #undef Seg
  72.  
  73. /*+-------------------------------------------------------------------------+
  74.   |                                                                         |
  75.   |                         write_executable_image                          |
  76.   |                                                                         |
  77.   +-------------------------------------------------------------------------+*/
  78. void write_executable_image()
  79. BeginDeclarations
  80. bit_32                                 data_index;
  81. bit_32                                 gap;
  82. bit_32                                 partial_length;
  83. lseg_ptr                               lseg;
  84. #define Lseg                           (*lseg)
  85. segment_entry_ptr                      seg;
  86. #define Seg                            (*seg)
  87. EndDeclarations
  88. BeginCode
  89.  exec_image_start_time = Now;
  90. /*+-------------------------------------------------------------------------+
  91.   |                                                                         |
  92.   |                         Validate start address.                         |
  93.   |                                                                         |
  94.   +-------------------------------------------------------------------------+*/
  95.  If start_address_found IsTrue
  96.   Then
  97.    fixup                 = start_address;
  98.    initial_CS            = CanonicFrame(frame());
  99.    initial_IP            = Bit_16(target() - frame());
  100.    If (comfile.val IsTrue)      AndIf 
  101.       (initial_CS IsNotZero)    AndIf 
  102.       (initial_IP IsNot 0x0100)
  103.     Then  /* COM file start address must be 0000:0100 */
  104.       linker_error(4, "Start address for COM file is not 0000:0100.\n");
  105.     Else
  106.      If (sysfile.val IsTrue)   AndIf
  107.         (initial_CS IsNotZero) AndIf 
  108.         (initial_IP IsNotZero)
  109.       Then  /* SYS file start address must be 0000:0000 */
  110.         linker_error(4, "Start address for SYS file is not 0000:0000.\n");
  111.       EndIf;
  112.     EndIf;
  113.   Else  /* No start address found. */
  114.    linker_error(4,"No start address.\n");
  115.    initial_CS = 0;
  116.    initial_IP = 0;
  117.   EndIf;
  118. /*+-------------------------------------------------------------------------+
  119.   |                                                                         |
  120.   |                        Validate stack segment.                          |
  121.   |                                                                         |
  122.   +-------------------------------------------------------------------------+*/
  123.  If (comfile.val IsTrue) AndIf (stack_segment_found IsTrue)
  124.   Then  /* COM file should not have a stack segment. */
  125.     linker_error(4, "COM file should not have a stack segment.\n");
  126.   Else
  127.    If (sysfile.val IsTrue) AndIf (stack_segment_found IsTrue)
  128.     Then  /* SYS file should not have a stack segment. */
  129.       linker_error(4, "SYS file should not have a stack segment.\n");
  130.     Else
  131.      If (exefile IsTrue) AndIf (stack_segment_found IsFalse)
  132.       Then  /* EXE file should have a stack segment. */
  133.        linker_error(4, "EXE file should have a stack segment.\n");
  134.       EndIf;
  135.     EndIf;
  136.   EndIf;
  137.  
  138.  If pause.val IsTrue
  139.   Then
  140.    printf("About to write \"%Fs\".\n", (*exe_file_list.first).filename);
  141.    printf("Press [RETURN] key to continue.\n");
  142.    gets(CharPtr(object_file_element));
  143.   EndIf;
  144.  file_open_for_write(exe_file_list.first);
  145.  If exefile IsTrue
  146.   Then
  147.    make_EXE_header();
  148.   Else
  149.    highest_uninitialized_byte = (*segment_list.last).address +
  150.                                 (*segment_list.last).length;
  151.   EndIf;
  152. /*+-------------------------------------------------------------------------+
  153.   |                                                                         |
  154.   |     Well, we have everything we need to write the executable image.     |
  155.   |                            So let's do it!                              |
  156.   |                                                                         |
  157.   +-------------------------------------------------------------------------+*/
  158.  /* We will use object_file_element as a source for the gaps caused by
  159.     the alignment of segments.  We will fill the gaps with zeros. */
  160.  far_set(BytePtr(object_file_element), 0, MAX_ELEMENT_SIZE);
  161.  next_available_address = address_base;
  162.  TraverseList(segment_list, seg)
  163.   BeginTraverse
  164.    LoopIf((*Seg.lsegs.first).align Is absolute_segment);
  165.    ExitIf(Seg.address NotLessThan highest_uninitialized_byte);
  166.    TraverseList(Seg.lsegs, lseg)
  167.     BeginTraverse
  168.      ExitIf(Lseg.address NotLessThan highest_uninitialized_byte);
  169.      If Lseg.address LessThan next_available_address
  170.       Then
  171.        LoopIf((Lseg.address+Lseg.length) NotGreaterThan 
  172.               next_available_address);
  173.        data_index     = next_available_address - Lseg.address;
  174.        partial_length = Lseg.length - data_index;
  175.        If Seg.combine IsNot blank_common_combine
  176.         Then
  177.          file_write(Addr(Lseg.data[Bit_16(data_index)]), partial_length);
  178.         Else
  179.          write_gap(partial_length);
  180.         EndIf;
  181.       Else
  182.        gap = Lseg.address - next_available_address;
  183.        If gap IsNotZero
  184.         Then
  185.          write_gap(gap);
  186.          next_available_address += gap;
  187.         EndIf;
  188.        If (Lseg.address + Lseg.length) Exceeds highest_uninitialized_byte
  189.         Then
  190.          partial_length = (Lseg.address + Lseg.length) - 
  191.                           highest_uninitialized_byte;
  192.          If Seg.combine IsNot blank_common_combine
  193.           Then
  194.            file_write(Lseg.data, partial_length);
  195.           Else
  196.            write_gap(partial_length);
  197.           EndIf;
  198.         Else
  199.          If Seg.combine IsNot blank_common_combine
  200.           Then
  201.            file_write(Lseg.data, Lseg.length);
  202.           Else
  203.            write_gap(Lseg.length);
  204.           EndIf;
  205.          next_available_address += Lseg.length;
  206.         EndIf;
  207.       EndIf;
  208.     EndTraverse;
  209.   EndTraverse;
  210.  file_close_for_write();
  211.  return;
  212. EndCode
  213. #undef Lseg
  214. #undef Seg
  215.  
  216. /*+-------------------------------------------------------------------------+
  217.   |                                                                         |
  218.   |                                write_gap                                |
  219.   |                                                                         |
  220.   +-------------------------------------------------------------------------+*/
  221. void write_gap(bit_32 length)
  222. BeginDeclarations
  223. EndDeclarations
  224. BeginCode
  225.  While length Exceeds 0
  226.   BeginWhile
  227.    If length Exceeds Bit_32(MAX_ELEMENT_SIZE)
  228.     Then
  229.      file_write(BytePtr(object_file_element), Bit_32(MAX_ELEMENT_SIZE));
  230.      length -= Bit_32(MAX_ELEMENT_SIZE);
  231.     Else
  232.      file_write(BytePtr(object_file_element), length);
  233.      length = 0L;
  234.     EndIf;
  235.   EndWhile;
  236.  return;
  237. EndCode
  238.  
  239.  
  240.