Crossware

Table of Contents        Previous topic       Next topic       

LINKER->Linker Command Line Options->Generate Relocatable Binary Output (/RBIN)

This option causes the program code to be generated in as a binary image of target memory (as for the /BIN option) and appends a relocation table to the front of the file.  A smart loader can use this relocation table to update the program so that it will run correctly at the address into which it has been loaded.
    
The format for the file is:

All 4 byte values are store most significant byte first.

Typically the program will be compiled to run at address zero with both code and data in ram (/NOROM option).  The loader will then add the load address to all of the locations pointed to by the relocation table.

The following DOS program will convert a relocatable binary image file into a binary image file and illustrates how a smart loader should handle the relocation table.


#include <stdio.h>
#include <stdlib.h>
#include <string.h>


long GetLong(FILE* fp);

void main(int argc, char *argv[])
{
 long nRelocationOffset;
 char* pszFilename;
 FILE* fpInput;
 FILE* fpOutput;
 char szOutfile[_MAX_PATH];
 long nProgramOffset;
 char nByte;
 if (argc < 3)
 {
   printf("Usage: rbin2bin <input filename> <relocation offset (decimal)>\n");
   exit(1);
 }
 nRelocationOffset = atol(argv[2]);
 pszFilename = argv[1];
 fpInput = fopen(pszFilename, "rb");
 if (fpInput == NULL)
 {
   printf("Cannot open file %s for input\n", pszFilename);
   exit(1);
 }
 strcpy(szOutfile, pszFilename);
 strcat(szOutfile, ".BIN");
 fpOutput = fopen(szOutfile, "w+b"); // open for reading and writing
 if (fpOutput == NULL)
 {
   printf("Cannot open file %s for output\n", szOutfile);
   exit(1);
 }
 else
 {
   printf("Creating output file %s\n", szOutfile);
 }
 // read the first 4 bytes to get to the position of the start of the program bytes
 nProgramOffset = GetLong(fpInput);
 fseek(fpInput, nProgramOffset, SEEK_SET); // move to the start of the program
 // copy the complete program to the output file
 while (1)
 {
   nByte = fgetc(fpInput);
   if (nByte == EOF)
   {
     if (feof(fpInput) != 0)
       break;  // it's a genuine end of file
   }
   putc((int)nByte, fpOutput);
 };
 if (nRelocationOffset != 0)
 {
   // now read the relocation table and modify the output file
   fseek(fpInput, 4, SEEK_SET);  // move to the start of the relocation table
   while (ftell(fpInput) < nProgramOffset)
   {
     long nAddress;
     long temp = ftell(fpInput);
     // keep going until we get to the program bytes
     long nOffset = GetLong(fpInput);
     fseek(fpOutput, nOffset, SEEK_SET); // move to the position in the output file
     nAddress = GetLong(fpOutput); // read the bytes to be modify
     nAddress += nRelocationOffset;
     fseek(fpOutput, nOffset, SEEK_SET); // move back to the position in the output file
     // write the modified data back to the output file
     putc((int)(char)(nAddress >> 24), fpOutput);
     putc((int)(char)(nAddress >> 16), fpOutput);
     putc((int)(char)(nAddress >> 8), fpOutput);
     putc((int)(char)nAddress, fpOutput);
   }
 }
 fclose(fpInput);
 fclose(fpOutput);
}


long GetLong(FILE* fp)
{
 unsigned char nByte1 = fgetc(fp);
 unsigned char nByte2 = fgetc(fp);
 unsigned char nByte3 = fgetc(fp);
 unsigned char nByte4 = fgetc(fp);
 // construct the long value
 long nValue = (long)nByte1 << 24 | (long)nByte2 << 16 | (long)nByte3 << 8 | (long)nByte4;
 return nValue;
}