]> git.sur5r.net Git - cc65/blob - src/ar65/objfile.c
add gotox, gotoy, and gotoxy
[cc65] / src / ar65 / objfile.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 objfile.c                                 */
4 /*                                                                           */
5 /*                Object file handling for the ar65 archiver                 */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2012, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <string.h>
37 #include <errno.h>
38
39 /* common */
40 #include "cddefs.h"
41 #include "exprdefs.h"
42 #include "filestat.h"
43 #include "filetime.h"
44 #include "fname.h"
45 #include "symdefs.h"
46 #include "xmalloc.h"
47
48 /* ar65 */
49 #include "error.h"
50 #include "objdata.h"
51 #include "fileio.h"
52 #include "library.h"
53 #include "objfile.h"
54
55
56
57 /*****************************************************************************/
58 /*                                   Code                                    */
59 /*****************************************************************************/
60
61
62
63 static const char* GetModule (const char* Name)
64 /* Get a module name from the file name */
65 {
66     /* Make a module name from the file name */
67     const char* Module = FindName (Name);
68
69     /* Must not end with a path separator */
70     if (*Module == 0) {
71         Error ("Cannot make module name from `%s'", Name);
72     }
73
74     /* Done */
75     return Module;
76 }
77
78
79
80 static void ObjReadHeader (FILE* Obj, ObjHeader* H, const char* Name)
81 /* Read the header of the object file checking the signature */
82 {
83     H->Magic      = Read32 (Obj);
84     if (H->Magic != OBJ_MAGIC) {
85         Error ("`%s' is not an object file", Name);
86     }
87     H->Version    = Read16 (Obj);
88     if (H->Version != OBJ_VERSION) {
89         Error ("Object file `%s' has wrong version", Name);
90     }
91     H->Flags        = Read16 (Obj);
92     H->OptionOffs   = Read32 (Obj);
93     H->OptionSize   = Read32 (Obj);
94     H->FileOffs     = Read32 (Obj);
95     H->FileSize     = Read32 (Obj);
96     H->SegOffs      = Read32 (Obj);
97     H->SegSize      = Read32 (Obj);
98     H->ImportOffs   = Read32 (Obj);
99     H->ImportSize   = Read32 (Obj);
100     H->ExportOffs   = Read32 (Obj);
101     H->ExportSize   = Read32 (Obj);
102     H->DbgSymOffs   = Read32 (Obj);
103     H->DbgSymSize   = Read32 (Obj);
104     H->LineInfoOffs = Read32 (Obj);
105     H->LineInfoSize = Read32 (Obj);
106     H->StrPoolOffs  = Read32 (Obj);
107     H->StrPoolSize  = Read32 (Obj);
108     H->AssertOffs   = Read32 (Obj);
109     H->AssertSize   = Read32 (Obj);
110     H->ScopeOffs    = Read32 (Obj);
111     H->ScopeSize    = Read32 (Obj);
112     H->SpanOffs     = Read32 (Obj);
113     H->SpanSize     = Read32 (Obj);
114 }
115
116
117
118 static void SkipExpr (FILE* F)
119 /* Skip an expression in F */
120 {
121     /* Get the operation and skip it */
122     unsigned char Op = Read8 (F);
123
124     /* Handle then different expression nodes */
125     switch (Op) {
126
127         case EXPR_NULL:
128             break;
129
130         case EXPR_LITERAL:
131             /* 32 bit literal value */
132             (void) Read32 (F);
133             break;
134
135         case EXPR_SYMBOL:
136             /* Variable seized symbol index */
137             (void) ReadVar (F);
138             break;
139
140         case EXPR_SECTION:
141             /* 8 bit segment number */
142             (void) Read8 (F);
143             break;
144
145         default:
146             /* What's left are unary and binary nodes */
147             SkipExpr (F);   /* Left */
148             SkipExpr (F);   /* right */
149             break;
150     }
151 }
152
153
154
155 static void SkipLineInfoList (FILE* F)
156 /* Skip a list of line infos in F */
157 {
158     /* Number of indices preceeds the list */
159     unsigned long Count = ReadVar (F);
160
161     /* Skip indices */
162     while (Count--) {
163         (void) ReadVar (F);
164     }
165 }
166
167
168
169 void ObjReadData (FILE* F, ObjData* O)
170 /* Read object file data from the given file. The function expects the Name
171  * and Start fields to be valid. Header and basic data are read.
172  */
173 {
174     unsigned long Count;
175
176     /* Seek to the start of the object file data */
177     fseek (F, O->Start, SEEK_SET);
178
179     /* Read the object file header */
180     ObjReadHeader (F, &O->Header, O->Name);
181
182     /* Read the string pool */
183     fseek (F, O->Start + O->Header.StrPoolOffs, SEEK_SET);
184     Count = ReadVar (F);
185     CollGrow (&O->Strings, Count);
186     while (Count--) {
187         CollAppend (&O->Strings, ReadStr (F));
188     }
189
190     /* Read the exports */
191     fseek (F, O->Start + O->Header.ExportOffs, SEEK_SET);
192     Count = ReadVar (F);
193     CollGrow (&O->Exports, Count);
194     while (Count--) {
195
196         unsigned char ConDes[CD_TYPE_COUNT];
197
198         /* Skip data until we get to the name */
199         unsigned Type = ReadVar (F);
200         (void) Read8 (F);       /* AddrSize */
201         ReadData (F, ConDes, SYM_GET_CONDES_COUNT (Type));
202
203         /* Now this is what we actually need: The name of the export */
204         CollAppend (&O->Exports, CollAt (&O->Strings, ReadVar (F)));
205
206         /* Skip the export value */
207         if (SYM_IS_EXPR (Type)) {
208             /* Expression tree */
209             SkipExpr (F);
210         } else {
211             /* Literal value */
212             (void) Read32 (F);
213         }
214
215         /* Skip the size if necessary */
216         if (SYM_HAS_SIZE (Type)) {
217             (void) ReadVar (F);
218         }
219
220         /* Line info indices */
221         SkipLineInfoList (F);
222         SkipLineInfoList (F);
223     }
224 }
225
226
227
228 void ObjAdd (const char* Name)
229 /* Add an object file to the library */
230 {
231     struct stat StatBuf;
232     const char* Module;
233     ObjHeader H;
234     ObjData* O;
235
236     /* Open the object file */
237     FILE* Obj = fopen (Name, "rb");
238     if (Obj == 0) {
239         Error ("Could not open `%s': %s", Name, strerror (errno));
240     }
241
242     /* Get the modification time of the object file. There a race condition
243      * here, since we cannot use fileno() (non standard identifier in standard
244      * header file), and therefore not fstat. When using stat with the
245      * file name, there's a risk that the file was deleted and recreated
246      * while it was open. Since mtime and size are only used to check
247      * if a file has changed in the debugger, we will ignore this problem
248      * here.
249      */
250     if (FileStat (Name, &StatBuf) != 0) {
251         Error ("Cannot stat object file `%s': %s", Name, strerror (errno));
252     }
253
254     /* Read and check the header */
255     ObjReadHeader (Obj, &H, Name);
256
257     /* Make a module name from the file name */
258     Module = GetModule (Name);
259
260     /* Check if we already have a module with this name */
261     O = FindObjData (Module);
262     if (O == 0) {
263         /* Not found, create a new entry */
264         O = NewObjData ();
265     } else {
266         /* Found - check the file modification times of the internal copy
267          * and the external one.
268          */
269         if (difftime ((time_t)O->MTime, StatBuf.st_mtime) > 0.0) {
270             Warning ("Replacing module `%s' by older version in library `%s'",
271                      O->Name, LibName);
272         }
273
274         /* Free data */
275         ClearObjData (O);
276     }
277
278     /* Initialize the object module data structure */
279     O->Name     = xstrdup (Module);
280     O->Flags    = OBJ_HAVEDATA;
281     O->MTime    = (unsigned long) StatBuf.st_mtime;
282     O->Start    = 0;
283
284     /* Determine the file size. Note: Race condition here */
285     fseek (Obj, 0, SEEK_END);
286     O->Size     = ftell (Obj);
287
288     /* Read the basic data from the object file */
289     ObjReadData (Obj, O);
290
291     /* Copy the complete object data to the library file and update the
292      * starting offset
293      */
294     fseek (Obj, 0, SEEK_SET);
295     O->Start    = LibCopyTo (Obj, O->Size);
296
297     /* Done, close the file (we read it only, so no error check) */
298     fclose (Obj);
299 }
300
301
302
303 void ObjExtract (const char* Name)
304 /* Extract a module from the library */
305 {
306     FILE* Obj;
307
308     /* Make a module name from the file name */
309     const char* Module = GetModule (Name);
310
311     /* Try to find the module in the library */
312     const ObjData* O = FindObjData (Module);
313
314     /* Bail out if the module does not exist */
315     if (O == 0) {
316         Error ("Module `%s' not found in library `%s'", Module, LibName);
317     }
318
319     /* Open the output file */
320     Obj = fopen (Name, "w+b");
321     if (Obj == 0) {
322         Error ("Cannot open target file `%s': %s", Name, strerror (errno));
323     }
324
325     /* Copy the complete object file data from the library to the new object
326      * file.
327      */
328     LibCopyFrom (O->Start, O->Size, Obj);
329
330     /* Close the file */
331     if (fclose (Obj) != 0) {
332         Error ("Problem closing object file `%s': %s", Name, strerror (errno));
333     }
334
335     /* Set access and modification time */
336     if (SetFileTimes (Name, O->MTime) != 0) {
337         Error ("Cannot set mod time on `%s': %s", Name, strerror (errno));
338     }
339 }
340
341
342