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