Category : Assembly Language Source Code
Archive   : RLOCATE.ZIP
Filename : LOCATE.ASC

 
Output of file : LOCATE.ASC contained in archive : RLOCATE.ZIP

_LOCATION IS EVERYTHING!_
by Mark Nelson

[LISTING ONE]

/********************************************************************
** ---- LOCATE.C -----
** Copyright (C) 1989 by Mark R. Nelson
** Program: LOCATE.C
** Author: Mark R. Nelson
** Summary: LOCATE reads in MS-DOS formate EXE files and writes
** out relocated code in Intel Hex format. The code
** segment is relocated to start at F000:0000. Data
** is relocated to start at 0040:0000.
********************************************************************/

#include
#include

#define TRUE 1
#define FALSE 0

struct exe_header {
unsigned int signature;
unsigned int image_length_mod_512;
unsigned int file_size_in_pages;
unsigned int num_of_relocation_table_items;
unsigned int size_of_header_in_paragraphs;
unsigned int min_num_of_paragraphs_required;
unsigned int max_num_of_paragraphs_required;
unsigned int disp_of_stack_in_paragraphs;
unsigned int initial_sp;
unsigned int word_checksum;
unsigned int initial_ip;
unsigned int disp_of_code_in_paragraphs;
unsigned int disp_of_relocation_table;
unsigned int overlay_number;
} header;

FILE *exe_file;
FILE *hex_file;
unsigned char *image;
unsigned long int image_size;
unsigned long int image_offset;
unsigned long first_data_segment_in_exe_file;
int verbose=TRUE;
unsigned int output_base_code_segment=0xF000;
unsigned int output_base_data_segment=0x0040;

main(int argc,char *argv[])
{
printf("Locate 1.0 Copyright (C) 1989 by Mark R. Nelson\n");

open_files(argc,argv); /* Open the input and output files */
read_header_data(); /* Read in the EXE file header */
read_input(); /* Read the code image into a buffer */
process_relocation_table(); /* Relocate all segment references */
dump_output(); /* Write the code image to the HEX file */
output_restart_code(); /* Write the restart code line */
output_intel_hex(0,0,1,NULL); /* Output an EOF record */
Š}

/********************************************************************
** ---- open_files ----
** This routine opens an EXE file and a HEX file. If they are specified
** on the command line, those names are used. Otherwise the user is
** prompted for file names
********************************************************************/

open_files(int argc,char *argv[])
{
char exe_file_name[81];
char hex_file_name[81];

if (argc>1)
strcpy(exe_file_name,argv[1]);
else
{
printf("EXE file name? ");
scanf("%s",exe_file_name);
}

exe_file=fopen(exe_file_name,"rb");
if (exe_file==NULL)
fatal_error("Had trouble opening the input file!");

if (argc > 2)
strcpy(hex_file_name,argv[2]);
else
{
printf("Hex file name? ");
scanf("%s",hex_file_name);
}

hex_file=fopen(hex_file_name,"w");
if (hex_file==NULL)
fatal_error("Had trouble opening the output file!");

}

/********************************************************************
** ---- read_header_data ----
** This routine reads in the EXE header structure and computes both
** the image offset and size. The compuataions are all done using
** numbers found in the header. This program arbitrarily limits
** the code image size to 64K, but could easily be expanded to go
** to larger sizes.
********************************************************************/

read_header_data()
{
if (fread(&header,sizeof(struct exe_header),1,exe_file) != 1)
fatal_error("Couldn't read header from file!");
if (verbose)
print_header();
Š image_offset=header.size_of_header_in_paragraphs*16;
image_size = (header.file_size_in_pages-1)*512;
image_size -= image_offset;
image_size += header.image_length_mod_512;
if (image_size > 0xFFFFL)
fatal_error("The EXE image is larger than I can handle!");
first_data_segment_in_exe_file=header.disp_of_stack_in_paragraphs;
}

/********************************************************************
** ---- read_input --
** This routine reads the code image into a buffer. Any trouble with
** the buffer or the file generates a fatal error.
********************************************************************/

read_input()
{
image=malloc(image_size);
if (image==NULL)
fatal_error("Couldn't allocate output image space!");
if (fseek(exe_file,image_offset,SEEK_SET) != 0)
fatal_error("Couldn't seek to image in the input file!");
if (fread(image,1,(int)image_size,exe_file) != (int)image_size)
fatal_error("Couldn't read in the image!");
}

/********************************************************************
** ---- process_relocation_table ----
** This routine loops through all of the entries in the relocation
** table. Each entry points to a segment value in the code image.
** That segment value is checked to see if it points to code or
** data. If it points to data, it is relocated to start at the
** output_base_data_segment. Code segments are relocated to start
** at output_base_code_segment.
********************************************************************/

process_relocation_table()
{
int i;
unsigned int reloc[2];
unsigned long int spot;
unsigned int *guy;
unsigned int old_value;
unsigned int new_value;

fseek(exe_file,(long)header.disp_of_relocation_table,0);
for (i=0;i {
if (fread(reloc,2,2,exe_file) != 2)
fatal_error("Couldn't read relocation data from file!");
printf("Record %3d: %04X:%04X:",i,reloc[1],reloc[0]);
spot=reloc[1]*16 + reloc[0];
old_value=*(int *)(image+spot);
printf(" was: %04X", old_value);
if (old_value < first_data_segment_in_exe_file)
Š new_value=old_value+output_base_code_segment;
else
new_value=old_value-first_data_segment_in_exe_file+output_base_data_segment;
*(int *)(image+spot)=new_value;
printf(" now is: %04X\r", new_value);
}
printf("\n");
}

/********************************************************************
** ---- dump_output ----
** This routine loops the entire code image. It outputs 34 bytes
** at a time in Intel Hex format until it is done. While it is
** doing this it keeps the user posted by writing the addresses
** to the screen. Note that this module would need some modifications
** to handle images greater than 64K.
********************************************************************/

dump_output()
{
unsigned char *output_pointer;
long int output_size;
int record_size;
unsigned int output_address;
unsigned char segment_address[2];

output_pointer=image;
output_size=image_size;
output_address=0;
segment_address[0]=output_base_code_segment>>8;
segment_address[1]=output_base_code_segment & 0xff;
output_intel_hex(2,0,2,segment_address);
while (output_size > 0)
{
printf("%04X\r",output_address);
record_size=(output_size > 34) ? 34 : output_size;
output_intel_hex(record_size,output_address,0,output_pointer);
output_pointer += record_size;
output_size -= record_size;
output_address += record_size;
}
printf("\n");
}

/********************************************************************
** ---- output_restart_code ----
** This routine writes a JMP START instruction out at location
** at FFFF:0000. The address of START is contained in the EXE
** header block.
********************************************************************/

output_restart_code()
{
unsigned char jmp_code[5];
unsigned char segment_address[2];
Š
segment_address[0]=0xff;
segment_address[1]=0xff;
output_intel_hex(2,0,2,segment_address);
jmp_code[0]=0xea; /* JMP ????:???? */
jmp_code[1]=header.initial_ip & 0xff;
jmp_code[2]=header.initial_ip >> 8;
header.disp_of_code_in_paragraphs += output_base_code_segment;
jmp_code[3]=header.disp_of_code_in_paragraphs & 0xff;
jmp_code[4]=header.disp_of_code_in_paragraphs >> 8;
header.disp_of_code_in_paragraphs -= output_base_code_segment;
output_intel_hex(5,0,0,jmp_code);
}

/********************************************************************
** ---- output_intel_hex ----
** This routine writes a single record of Intel Hex.
********************************************************************/

output_intel_hex(int size,unsigned int address,int type,unsigned char buffer[])
{
int checksum;
int i;

fprintf(hex_file,":%02X%04X%02X",size,address,type);
checksum=size+address+(address>>8)+type;
for (i=0;i {
fprintf(hex_file,"%02X",buffer[i]);
checksum += buffer[i];
}
checksum = -checksum & 0xff;
fprintf(hex_file,"%02X\n",checksum);
}

/********************************************************************
** ---- print_header ----
** This is a routine that lets the program print out the contents
** of the header. It is here primarily for assistance in debugging.
********************************************************************/

print_header()
{
printf("Link program signature: ");
printf("%4.4X\n",header.signature);
printf("Length of image mod 512: ");
printf("%4.4X\n",header.image_length_mod_512);
printf("Size of file in 512 byte pages, including header: ");
printf("%4.4X\n",header.file_size_in_pages);
printf("Number of relocation table items: ");
printf("%4.4X\n",header.num_of_relocation_table_items);
printf("Size of header in 16 byte paragraphs: ");
printf("%4.4X\n",header.size_of_header_in_paragraphs);
printf("Minimum # of 16 byte paragraphs needed above program: ");
printf("%4.4X\n",header.min_num_of_paragraphs_required);
Š printf("Maximum # of 16 byte paragraphs needed above program: ");
printf("%4.4X\n",header.max_num_of_paragraphs_required);
printf("Displacement of stack within load module in paragraphs: ");
printf("%4.4X\n",header.disp_of_stack_in_paragraphs);
printf("Offset to be loaded in SP: ");
printf("%4.4X\n",header.initial_sp);
printf("Word checksum: ");
printf("%4.4X\n",header.word_checksum);
printf("Offset to be loaded in IP: ");
printf("%4.4X\n",header.initial_ip);
printf("Displacement of code segment in 16 byte paragraphs: ");
printf("%4.4X\n",header.disp_of_code_in_paragraphs);
printf("Displacement of 1st relocation table item: ");
printf("%4.4X\n",header.disp_of_relocation_table);
printf("Overlay number: ");
printf("%4.4X\n",header.overlay_number);
}
/********************************************************************
** ---- fatal_error ----
** A self-documenting utility.
********************************************************************/

fatal_error(char *message)
{
printf(message);
exit(1);
}

[LISTING TWO]

;********************************************************************
; ---- START.ASM ----
; Copyright (C) 1989 by Mark R. Nelson
; Module: START.ASM
; Author: Mark R. Nelson
; Summary: This module is an alternate startup routine for Microsoft
; or Turbo C programs running on non DOS hardware. It has
; three main jobs. First, it sets up the segment definitions
; so that the STACK segment is the first segment in RAM.
; Second, it initializes all predefined data. Third, it jumps
; to the user's main() routine.
;*******************************************************************

;
; Note here that if DGROUP does not contain the stack, which may
; be true for larger models, the STACK segment needs to be moved
; to be the first one after END_OF_ROM.
;
; Also note that for the startup code to work properly, the first
; segment in the data area must be paragraph aligned. This insures
; that for the startup code, the first data segment is exactly 3
; larger than the END_OF_ROM segment.
;
_TEXT SEGMENT BYTE PUBLIC 'CODE'
_TEXT ENDS
END_OF_ROM SEGMENT PARA PUBLIC 'STARTUP_CODE'
END_OF_ROM ENDS
_CONST SEGMENT PARA PUBLIC 'CONST'
_CONST ENDS
_BSS SEGMENT WORD PUBLIC 'BSS'
_BSS ENDS
_DATA SEGMENT WORD PUBLIC 'DATA'
_DATA ENDS
_STACK SEGMENT WORD STACK 'STACK'

MYSTACK DB 512 DUP (?)

_STACK ENDS
;
; Note here that if DGROUP does not contain the stack, which may
; be true for larger models, the STACK segment needs to be moved
; to be the first one after END_OF_ROM.
;
DGROUP GROUP _CONST,_BSS,_DATA,_STACK

extrn _main:far

public __acrtused ;This value makes many of the
__acrtused = 9876h ;library routines happy

END_OF_ROM SEGMENT PARA PUBLIC 'STARTUP_CODE'

ASSUME CS:END_OF_ROM

Š PUBLIC START

START PROC FAR

MOV AX,DGROUP ;This code initializes the
MOV SS,AX ;SS:SP pair with the proper
MOV SP,OFFSET MYSTACK+512 ;values.
;
; This section of code is charged with moving all predefined values out
; of ROM and into RAM. This is done by copying all values out of the
; part of ROM immediately following the last code segment into the
; data section.
;
MOV AX,CS ;The present code segment is the
ADD AX,3 ;last code segment, and we know
MOV DS,AX ;that the first data segment will
;be three up form here. Put that
;value into DS

MOV AX,DGROUP ;Now set ES to point to the first
MOV ES,AX ;section of RAM.
XOR SI,SI ;SI and DI are the registers
XOR DI,DI ;used in the MOVSB instruction.
MOV CX,0FBFFH ;This rep instruction will fill
REP MOVSB ;everything in a 64K RAM following
;the interrupt vector space.

MOV AX,ES ;Now set up DS to point to DGROUP
MOV DS,AX
STI ;Enable interrupts and the jump
JMP _main ;to the start of the C code

START ENDP

END_OF_ROM ENDS

END START


[LISTING THREE]

/********************************************************************
** ---- HELLO.C -----
** Copyright (C) 1989 by Mark R. Nelson
** Program: HELLO.C
** Author: Mark R. Nelson
** Summary: Hello demonstrates the LOCATE program. It simulates
** output of a string to a printer on an embedded system.
********************************************************************/

main()
{

my_print("Hello, world!\n");
while (1) ;
}

my_print(char *message)
{
while (*message)
{
if (*message=='\n')
{
while ((inportb(0x200) & 0x80) == 0) ;
outportb(0x200,'\r');
}
while ((inportb(0x200) & 0x80) == 0) ;
outportb(0x200,*message++);
}
}