Skip to content

Commit 2dabca2

Browse files
committed
some c code related to OBJ format
1 parent 9f8c238 commit 2dabca2

File tree

7 files changed

+1209
-0
lines changed

7 files changed

+1209
-0
lines changed

Info/Code/C/BINTOOBJ/BINTOOBJ.C

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
/*
2+
This material has been placed in the public domain and as such there are no
3+
limitations on its use. I do ask however that an acknowledgement is made if
4+
this helps you out and the header remains intact in the source (yes I've got
5+
an ego too folks). As is usually the case, no warranties explicitly or
6+
implied is made with this stuff.
7+
8+
This program takes any binary file and converts it to an .OBJ file which can
9+
be linked with your application. Two symbols are defined at the start and end
10+
of the data through which you can address and size the information.
11+
12+
If you want more information regarding the operation, see the acompanying .TXT
13+
file. Apologies for the terseness of the comments, but the object record
14+
structure and contents are well documented.
15+
16+
A successful compilation & link can be achieved using MSC 7 with:
17+
18+
CL /AL /Za /W4 /WX bintoobj.c
19+
20+
Lee Brown Compuserve: 100325,3304
21+
*/
22+
23+
#include <malloc.h>
24+
#include <stdio.h>
25+
#include <stdlib.h>
26+
#include <string.h>
27+
#include <io.h>
28+
#include <fcntl.h>
29+
#include <sys\types.h>
30+
#include <sys\stat.h>
31+
32+
33+
/* Readability */
34+
35+
typedef unsigned int uint;
36+
typedef unsigned char ubyte;
37+
typedef unsigned long ulong;
38+
39+
#define WriteRecord( fh, ObjRec ) _write( (fh), (char *)(ObjRec), \
40+
3 + *(uint *)((ObjRec)+1) )
41+
42+
43+
/* Manifests */
44+
45+
#define SEGDEF_ALIGN_REL_B_LSEG 1
46+
#define SEGDEF_COMBINE_PUBLIC 2
47+
#define SEGMENT_PREFIX "BINARY"
48+
#define SEGMENT_POSTFIX_SIZE 2 /* No. of digits to follow */
49+
#define SEGMENT_POSTFIX_SIZE_S "2" /* No. of digits to follow */
50+
51+
#define LLNAME_NULL 1
52+
#define LLNAME_FAR_DATA 2
53+
#define LLNAME_BINARY 3
54+
55+
#define EXIT_OK 0
56+
#define EXIT_WARNING 10
57+
#define EXIT_ERROR 20
58+
59+
60+
/* a safer way to allocate memory */
61+
62+
void *SafeMAlloc( uint length ) {
63+
void *ret;
64+
65+
if ( (ret = malloc( length )) != NULL )
66+
return ret;
67+
fprintf( stderr, "memory allocation failure.\n" );
68+
exit( EXIT_ERROR );
69+
}
70+
71+
72+
/* Calculate and store the checksum for a record */
73+
74+
ubyte CheckSum( ubyte *ObjRec ) {
75+
int CS = 0,
76+
i;
77+
for ( i = *(uint *)(ObjRec+1)+3; i>1; i-- )
78+
CS += *ObjRec++;
79+
return (*ObjRec = (ubyte)(-CS) );
80+
}
81+
82+
/* write a THEADR record */
83+
84+
void writeTHEADR( int out, char *Name ) {
85+
ubyte Buf[32];
86+
int NameLen = strlen( Name );
87+
88+
Buf[0] = 0x80; /* Identifier */
89+
*(uint *)(Buf+1) = NameLen + 2; /* Record length */
90+
Buf[3] = (ubyte)NameLen; /* name length */
91+
strncpy( (char *)(Buf+4), Name, NameLen ); /* name */
92+
CheckSum( Buf ); /* store checksum */
93+
WriteRecord( out, Buf ); /* and write record */
94+
}
95+
96+
/* write a SEGDEF record. The Segname, Classname and Overlaynames are actually
97+
indexes into a table referenced by the LNAMES record */
98+
99+
void writeSEGDEF( int out, uint Align, uint Combine, ulong Length,
100+
uint Segname, uint Classname, uint Overlayname ) {
101+
ubyte Buf[32];
102+
103+
Buf[0] = 0x98; /* identifier */
104+
*(uint *)(Buf+1) = 7; /* Record length */
105+
Buf[3] = (ubyte)( (Align << 5) | (Combine << 2) | /* Alignment, combine */
106+
(Length == 65536L ? 2L : 0L ) ); /* and length bit 16 */
107+
*(uint *)(Buf+4) = (uint)(Length & 0x0000ffffL); /* length */
108+
Buf[6] = (ubyte)Segname; /* Segment name index */
109+
Buf[7] = (ubyte)Classname; /* Classname index */
110+
Buf[8] = (ubyte)Overlayname; /* Overlayname index */
111+
CheckSum( Buf );
112+
WriteRecord( out, Buf );
113+
}
114+
115+
116+
/* write an LEDATA record. The SegmentIndex is an index into the LNAME list
117+
*/
118+
119+
void writeLEDATA( int out, ubyte *Buffer, uint Bytes, uint SegmentIndex,
120+
uint Offset ) {
121+
ubyte *Buf = SafeMAlloc( 1040 );
122+
123+
Buf[0] = 0xa0; /* identifier */
124+
*(uint *)(Buf + 1) = Bytes + 4; /* record length */
125+
Buf[3] = (ubyte)SegmentIndex; /* segment name index */
126+
*(uint *)(Buf+4) = Offset; /* Offset into segment */
127+
memcpy( Buf+6, Buffer, Bytes ); /* actual data */
128+
CheckSum( Buf );
129+
WriteRecord( out, Buf );
130+
free( Buf );
131+
}
132+
133+
134+
/* write a MODEND record */
135+
136+
void writeMODEND( int out ) {
137+
ubyte Buf[32];
138+
139+
Buf[0] = 0x8a; /* identifier */
140+
*(uint *)(Buf+1) = 2; /* record length */
141+
Buf[3] = 0;
142+
CheckSum( Buf );
143+
WriteRecord( out, Buf );
144+
}
145+
146+
147+
/* create and write the LNAMES record */
148+
149+
void genLNAME( char **buffer, char *name ) {
150+
int namelen = strlen( name );
151+
*(ubyte *)(*buffer) = (ubyte)namelen;
152+
memcpy( *buffer + 1, name, namelen );
153+
*buffer += namelen + 1;
154+
}
155+
void generateLNAMES( int out, ulong Filelength ) {
156+
ubyte *Buf, *Bufptr;
157+
uint Segments = (uint)(( Filelength - 1) / 65536L + 1L);
158+
uint Namesize = strlen( SEGMENT_PREFIX ) + SEGMENT_POSTFIX_SIZE;
159+
uint i;
160+
161+
Buf = SafeMAlloc( 1024 );
162+
Bufptr = Buf+3;
163+
Buf[0] = 0x96;
164+
genLNAME( (char **)&Bufptr, "" );
165+
genLNAME( (char **)&Bufptr, "FAR_DATA" );
166+
for ( i = 0; i < Segments ; i++ ) {
167+
sprintf( (char *)(Bufptr+1), "%s%0" SEGMENT_POSTFIX_SIZE_S "d",
168+
SEGMENT_PREFIX, i );
169+
genLNAME( (char **)&Bufptr, (char *)(Bufptr+1) );
170+
}
171+
*(uint *)(Buf+1) = Bufptr - Buf + 1 - 3;
172+
CheckSum( Buf );
173+
WriteRecord( out, Buf );
174+
free( Buf );
175+
}
176+
177+
178+
/* write a PUBDEF record */
179+
180+
void writePUBDEF( int out, uint SegmentIndex, uint Offset, char *Name ) {
181+
ubyte Buf[64];
182+
int Namelen = strlen( Name );
183+
184+
Buf[0] = 0x90;
185+
*(uint *)(Buf+1) = Namelen + 7;
186+
Buf[3] = 0; /* group index */
187+
Buf[4] = (ubyte)SegmentIndex; /* segment index */
188+
Buf[5] = (ubyte)Namelen;
189+
strncpy( (char *)(Buf+6), Name, Namelen );
190+
*(uint *)(Buf+6+Namelen) = Offset;
191+
Buf[8+Namelen] = 0;
192+
CheckSum( Buf );
193+
WriteRecord( out, Buf );
194+
}
195+
196+
197+
void help( void ) {
198+
printf( "usage:\nBinToObj <infile> <outfile>\n" );
199+
exit( EXIT_ERROR );
200+
}
201+
202+
/* Once the command line has been parsed and the relevant file opened, the
203+
real thing starts. Two files are created, one the final output file, the
204+
other a temporary file.
205+
206+
The LNAMES are constructed on-the-fly (ok, so it's not necessary for this,
207+
but it seemed like a good idea at the time...)
208+
209+
*/
210+
int BinToObj( char **argv ) {
211+
int in, out;
212+
uint BytesRead, Offset, Segment;
213+
ulong BytesLeft, i, TotalBytes;
214+
char *Buffer,
215+
NameBuf[32],
216+
*TempFile = "$$$TMP$.$$$";
217+
218+
if ( (in = _open( *++argv, _O_BINARY | _O_RDONLY )) == -1 ) {
219+
printf( "Can't open '%s'\n", *argv );
220+
return EXIT_ERROR;
221+
}
222+
if ( (out = _open( *++argv, _O_BINARY | _O_WRONLY | _O_TRUNC | _O_CREAT,
223+
_S_IREAD | _S_IWRITE )) == -1 ) {
224+
printf( "Can't create '%s'\n", *argv );
225+
return EXIT_ERROR;
226+
}
227+
writeTHEADR( out, *argv );
228+
TotalBytes = BytesLeft = _filelength( in );
229+
generateLNAMES( out, TotalBytes );
230+
Buffer = SafeMAlloc( 1024 );
231+
for ( Segment = 0; BytesLeft; Segment++ ) {
232+
sprintf( NameBuf, "BINARY%02d", Segment );
233+
writeSEGDEF( out, SEGDEF_ALIGN_REL_B_LSEG, SEGDEF_COMBINE_PUBLIC,
234+
__min( BytesLeft, 65536 ), Segment + LLNAME_BINARY,
235+
LLNAME_FAR_DATA, LLNAME_NULL );
236+
if ( Segment == 0 )
237+
writePUBDEF( out, Segment+1, 0, "_RawExeStart" );
238+
if ( BytesLeft < 65536 )
239+
writePUBDEF( out, Segment+1, (uint)BytesLeft, "_RawExeEnd" );
240+
for ( Offset = 0, i = __min( BytesLeft, 65536 ); i; i -= BytesRead,
241+
Offset += 1024 ) {
242+
BytesRead = _read( in, Buffer, (uint)__min( 1024, BytesLeft ) );
243+
writeLEDATA( out, (ubyte *)Buffer, BytesRead, Segment+1, Offset );
244+
BytesLeft -= BytesRead;
245+
}
246+
}
247+
writeMODEND( out );
248+
_close( out );
249+
_close( in );
250+
return 0;
251+
}
252+
253+
int main( int argc, char **argv ) {
254+
if ( argc != 3 )
255+
help();
256+
257+
return BinToObj( argv );
258+
}
259+

Info/Code/C/BINTOOBJ/BINTOOBJ.H

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#ifndef _BINTOOBJ_H
2+
#define _BINTOOBJ_H
3+
extern char __huge RawExeStart,
4+
__huge RawExeEnd;
5+
#endif
6+

Info/Code/C/BINTOOBJ/BINTOOBJ.TXT

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
Contents
2+
--------
3+
0. Introduction
4+
1. Synopsis
5+
2. How it works
6+
3. Compiler
7+
4. Example
8+
5. Wrap up
9+
6. File list
10+
11+
12+
0. Introduction
13+
---------------
14+
15+
This material has been placed in the public domain and as such there are no
16+
limitations on its use. I do ask however that an acknowledgement is made if
17+
this helps you out and the header remains intact in the source (yes I've got
18+
an ego too folks). As is usually the case, no warranties explicitly or
19+
implied is made with this stuff.
20+
21+
22+
1. Synopsis
23+
-----------
24+
25+
This program takes any binary file and converts it to an .OBJ file which can
26+
be linked with your application. Two symbols are defined at the start and end
27+
of the data through which you can address and size the information.
28+
29+
Where more than 64K is required, multiple segments are created being named
30+
BINARY00, BINARY01 .. BINARY99.
31+
32+
33+
2. How it works
34+
---------------
35+
36+
The following object records are created:
37+
38+
THEADR
39+
LNAMES
40+
SEGDEF } Multiple segments
41+
[PUBDEF] } may be output
42+
LEDATA } depending on size
43+
MODEND
44+
45+
The optional PUBDEF are output for both the first and last (or both if there
46+
is only one segment) declaring the symbols _RawExeStart and _RawExeEnd which
47+
may be referenced from within C (as RawExeStart and RawExeEnd) or ASM and give
48+
the address of the start and the byte following the end of the data written.
49+
See the accompanying EXAMPLE.C and BINTOOBJ.H for examples of how to use
50+
these symbols.
51+
52+
The LEDATA segments are called BINARY00, BINARY01 .. and have a classname of
53+
'FAR_DATA' to combine them in the correct area in the link file.
54+
55+
If you want more information about the object module, I suggest you get hold
56+
of an object module dump program (such as TDUMP in the Compuserve BCPPDOS
57+
forum) and see what's going on.
58+
59+
60+
3. Compilers
61+
------------
62+
Microsoft C 7.00 was used to compile this, using a command line of:
63+
64+
CL /AL /Za /W4 /WX bintoobj.c
65+
66+
As this is the most stringent error checking I can get, I'll assume the code
67+
is reasonably portable to another compiler.
68+
69+
70+
4. Example
71+
----------
72+
73+
Supplied is a small example of how to use the output from BinToObj. The
74+
example program simply prints a file to stdout. The .TXT file is embedded
75+
directly into the final .EXE though (this is a bit like those README.COM
76+
producing programs, though not as extensive). The code has been tested using
77+
a 100K .TXT file with no problems.
78+
79+
A small header is printed first followed by the text. The output may be
80+
redirected and compared against the original text.
81+
82+
83+
5. Wrap up
84+
----------
85+
86+
Any suggestions, improvements, etc. are all welcome. You can contact me via
87+
email at the address below.
88+
89+
90+
6. File list
91+
------------
92+
93+
BINtoOBJ.txt (this file)
94+
BINtoOBJ.c
95+
BINtoOBJ.h }
96+
makefile } Example usage
97+
example.c }
98+
99+
Lee Brown Compuserve: 100325,3304
100+

0 commit comments

Comments
 (0)