1 /* asmcode.c */
2 /*****************************************************************************/
3 /* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only                     */
4 /*                                                                           */
5 /* AS-Portierung                                                             */
6 /*                                                                           */
7 /* Verwaltung der Code-Datei                                                 */
8 /*                                                                           */
9 /*****************************************************************************/
10 
11 #include "stdinc.h"
12 #include <string.h>
13 
14 #include "version.h"
15 #include "endian.h"
16 #include "chunks.h"
17 #include "as.h"
18 #include "asmdef.h"
19 #include "errmsg.h"
20 #include "strutil.h"
21 #include "asmsub.h"
22 #include "asmpars.h"
23 #include "asmrelocs.h"
24 #include "asmlist.h"
25 #include "asmlabel.h"
26 
27 #include "asmcode.h"
28 
29 #define CodeBufferSize 512
30 
31 static Word LenSoFar;
32 static LongInt RecPos, LenPos;
33 static Boolean ThisRel;
34 
35 static Word CodeBufferFill;
36 static Byte *CodeBuffer;
37 
38 PPatchEntry PatchList, PatchLast;
39 PExportEntry ExportList, ExportLast;
40 LongInt SectSymbolCounter;
41 String SectSymbolName;
42 
FlushBuffer(void)43 static void FlushBuffer(void)
44 {
45   if (CodeBufferFill > 0)
46   {
47     if (fwrite(CodeBuffer, 1, CodeBufferFill, PrgFile) != CodeBufferFill)
48       ChkIO(ErrNum_FileWriteError);
49     CodeBufferFill = 0;
50   }
51 }
52 
DreheCodes(void)53 void DreheCodes(void)
54 {
55   int z;
56   LongInt l = CodeLen * Granularity();
57 
58   switch (ActListGran)
59   {
60     case 2:
61       for (z = 0; z < l >> 1; z++)
62         WAsmCode[z] = ((WAsmCode[z] & 0xff) << 8) + ((WAsmCode[z] & 0xff00) >> 8);
63       break;
64     case 4:
65       for (z = 0; z < l >> 2; z++)
66       {
67         LongWord Dest;
68         int z2;
69 
70         for (z2 = 0, Dest = 0; z2 < 4; z2++)
71         {
72           Dest = (Dest << 8) | (DAsmCode[z] & 0xff);
73           DAsmCode[z] >>= 8;
74         }
75         DAsmCode[z] = Dest;
76       }
77       break;
78   }
79 }
80 
WrPatches(void)81 static void WrPatches(void)
82 {
83   LongWord Cnt, ExportCnt, StrLen;
84   Byte T8;
85 
86   if (PatchList || ExportList)
87   {
88     /* find out length of string field */
89 
90     Cnt = StrLen = 0;
91     for (PatchLast = PatchList; PatchLast; PatchLast = PatchLast->Next)
92     {
93       Cnt++;
94       StrLen += (PatchLast->len = strlen(PatchLast->Ref) + 1);
95     }
96     ExportCnt = 0;
97     for (ExportLast = ExportList; ExportLast; ExportLast = ExportLast->Next)
98     {
99       ExportCnt++;
100       StrLen += (ExportLast->len = strlen(ExportLast->Name) + 1);
101     }
102 
103     /* write header */
104 
105     T8 = FileHeaderRelocInfo;
106     if (fwrite(&T8, 1, 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
107     if (!Write4(PrgFile, &Cnt)) ChkIO(ErrNum_FileWriteError);
108     if (!Write4(PrgFile, &ExportCnt)) ChkIO(ErrNum_FileWriteError);
109     if (!Write4(PrgFile, &StrLen)) ChkIO(ErrNum_FileWriteError);
110 
111     /* write patch entries */
112 
113     StrLen = 0;
114     for (PatchLast = PatchList; PatchLast; PatchLast = PatchLast->Next)
115     {
116       if (!Write8(PrgFile, &(PatchLast->Address))) ChkIO(ErrNum_FileWriteError);
117       if (!Write4(PrgFile, &StrLen)) ChkIO(ErrNum_FileWriteError);
118       if (!Write4(PrgFile, &(PatchLast->RelocType))) ChkIO(ErrNum_FileWriteError);
119       StrLen += PatchLast->len;
120     }
121 
122     /* write export entries */
123 
124     for (ExportLast = ExportList; ExportLast; ExportLast = ExportLast->Next)
125     {
126       if (!Write4(PrgFile, &StrLen)) ChkIO(ErrNum_FileWriteError);
127       if (!Write4(PrgFile, &(ExportLast->Flags))) ChkIO(ErrNum_FileWriteError);
128       if (!Write8(PrgFile, &(ExportLast->Value))) ChkIO(ErrNum_FileWriteError);
129       StrLen += ExportLast->len;
130     }
131 
132     /* write string table, free structures */
133 
134     while (PatchList)
135     {
136       PatchLast = PatchList;
137       if (fwrite(PatchLast->Ref, 1, PatchLast->len, PrgFile) != PatchLast->len) ChkIO(ErrNum_FileWriteError);
138       free(PatchLast->Ref);
139       PatchList = PatchLast->Next;
140       free(PatchLast);
141     }
142     PatchLast = NULL;
143 
144     while (ExportList)
145     {
146       ExportLast = ExportList;
147       if (fwrite(ExportLast->Name, 1, ExportLast->len, PrgFile) != ExportLast->len) ChkIO(ErrNum_FileWriteError);
148       free(ExportLast->Name);
149       ExportList = ExportLast->Next;
150       free(ExportLast);
151     }
152     ExportLast = NULL;
153   }
154 }
155 
156 /*--- neuen Record in Codedatei anlegen.  War der bisherige leer, so wird ---
157  ---- dieser ueberschrieben. ------------------------------------------------*/
158 
WrRecHeader(void)159 static void WrRecHeader(void)
160 {
161   Byte b;
162 
163   /* assume simple record without relocation info */
164 
165   ThisRel = RelSegs;
166   b = ThisRel ? FileHeaderRelocRec : FileHeaderDataRec;
167   if (fwrite(&b, 1, 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
168   if (fwrite(&HeaderID, 1, 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
169   b = ActPC; if (fwrite(&b, 1, 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
170   b = Grans[ActPC]; if (fwrite(&b, 1, 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
171   fflush(PrgFile);
172 }
173 
NewRecord(LargeWord NStart)174 void NewRecord(LargeWord NStart)
175 {
176   LongInt h;
177   LongWord PC;
178   Byte Header;
179 
180   /* flush remaining code in buffer */
181 
182   FlushBuffer();
183 
184   /* zero length record which may be deleted ? */
185   /* do not write out patches at this place - they
186      will be merged with the next record. */
187 
188   if (LenSoFar == 0)
189   {
190     if (fseek(PrgFile, RecPos, SEEK_SET) != 0) ChkIO(ErrNum_FileReadError);
191     WrRecHeader();
192     h = NStart;
193     if (!Write4(PrgFile, &h)) ChkIO(ErrNum_FileWriteError);
194     LenPos = ftell(PrgFile);
195     if (!Write2(PrgFile, &LenSoFar)) ChkIO(ErrNum_FileWriteError);
196   }
197 
198   /* otherwise full record */
199 
200   else
201   {
202     /* store current position (=end of file) */
203 
204     h = ftell(PrgFile);
205 
206     /* do we have reloc. info? - then change record type */
207 
208     if (PatchList || ExportList)
209     {
210       fflush(PrgFile);
211       if (fseek(PrgFile, RecPos, SEEK_SET) != 0) ChkIO(ErrNum_FileReadError);
212       Header = ThisRel ? FileHeaderRRelocRec : FileHeaderRDataRec;
213       if (fwrite(&Header, 1, 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
214     }
215 
216     /* fill in length of record */
217 
218     fflush(PrgFile);
219     if (fseek(PrgFile, LenPos, SEEK_SET) != 0) ChkIO(ErrNum_FileReadError);
220     if (!Write2(PrgFile, &LenSoFar)) ChkIO(ErrNum_FileWriteError);
221 
222     /* go back to end of file */
223 
224     if (fseek(PrgFile, h, SEEK_SET) != 0) ChkIO(ErrNum_FileReadError);
225 
226     /* write out reloc info */
227 
228     WrPatches();
229 
230     /* store begin of new code record */
231 
232     RecPos = ftell(PrgFile);
233 
234     LenSoFar = 0;
235     WrRecHeader();
236     ThisRel = RelSegs;
237     PC = NStart;
238     if (!Write4(PrgFile, &PC)) ChkIO(ErrNum_FileWriteError);
239     LenPos = ftell(PrgFile);
240     if (!Write2(PrgFile, &LenSoFar)) ChkIO(ErrNum_FileWriteError);
241   }
242 #if 0
243   /* put in the hidden symbol for the relocatable segment ? */
244 
245   if ((RelSegs) && (strcmp(CurrFileName, "INTERNAL")))
246   {
247     as_snprintf(SectSymbolName, sizeof(SectSymbolName), "__%s_%d",
248                 NamePart(CurrFileName), (int)(SectSymbolCounter++));
249     AddExport(SectSymbolName, ProgCounter());
250   }
251 #endif
252 }
253 
254 /*--- Codedatei eroeffnen --------------------------------------------------*/
255 
OpenFile(void)256 void OpenFile(void)
257 {
258   Word h;
259 
260   errno = 0;
261   PrgFile = fopen(OutName, OPENWRMODE);
262   if (!PrgFile) ChkIO(ErrNum_OpeningFile);
263 
264   errno = 0;
265   h = FileMagic;
266   if (!Write2(PrgFile,&h)) ChkIO(ErrNum_FileWriteError);
267 
268   CodeBufferFill = 0;
269   RecPos = ftell(PrgFile);
270   LenSoFar = 0;
271   NewRecord(PCs[ActPC]);
272 }
273 
274 /*---- Codedatei schliessen -------------------------------------------------*/
275 
CloseFile(void)276 void CloseFile(void)
277 {
278   Byte Head;
279   String h;
280   LongWord Adr;
281 
282   as_snprintf(h, sizeof(h), "AS %s/%s-%s", Version, ARCHPRNAME, ARCHSYSNAME);
283 
284   NewRecord(PCs[ActPC]);
285   fseek(PrgFile, RecPos, SEEK_SET);
286 
287   if (StartAdrPresent)
288   {
289     Head = FileHeaderStartAdr;
290     if (fwrite(&Head,sizeof(Head), 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
291     Adr = StartAdr;
292     if (!Write4(PrgFile,&Adr)) ChkIO(ErrNum_FileWriteError);
293   }
294 
295   Head = FileHeaderEnd;
296   if (fwrite(&Head,sizeof(Head), 1, PrgFile) != 1) ChkIO(ErrNum_FileWriteError);
297   if (fwrite(h, 1, strlen(h), PrgFile) != strlen(h)) ChkIO(ErrNum_FileWriteError);
298   fclose(PrgFile);
299   if (Magic)
300     unlink(OutName);
301 }
302 
303 /*--- erzeugten Code einer Zeile in Datei ablegen ---------------------------*/
304 
WriteBytes(void)305 void WriteBytes(void)
306 {
307   Word ErgLen;
308 
309   if (CodeLen == 0)
310     return;
311   ErgLen = CodeLen * Granularity();
312   if ((TurnWords != 0) != (BigEndian != 0))
313     DreheCodes();
314   if (((LongInt)LenSoFar) + ((LongInt)ErgLen) > 0xffff)
315     NewRecord(PCs[ActPC]);
316   if (CodeBufferFill + ErgLen < CodeBufferSize)
317   {
318     memcpy(CodeBuffer + CodeBufferFill, BAsmCode, ErgLen);
319     CodeBufferFill += ErgLen;
320   }
321   else
322   {
323     FlushBuffer();
324     if (ErgLen < CodeBufferSize)
325     {
326       memcpy(CodeBuffer, BAsmCode, ErgLen);
327       CodeBufferFill = ErgLen;
328     }
329     else if (fwrite(BAsmCode, 1, ErgLen, PrgFile) != ErgLen)
330       ChkIO(ErrNum_FileWriteError);
331   }
332   LenSoFar += ErgLen;
333   if ((TurnWords != 0) != (BigEndian != 0))
334     DreheCodes();
335 }
336 
RetractWords(Word Cnt)337 void RetractWords(Word Cnt)
338 {
339   Word ErgLen;
340 
341   ErgLen = Cnt * Granularity();
342   if (LenSoFar < ErgLen)
343   {
344     WrError(ErrNum_ParNotPossible);
345     return;
346   }
347 
348   if (MakeUseList)
349     DeleteChunk(SegChunks + ActPC, ProgCounter() - Cnt, Cnt);
350 
351   PCs[ActPC] -= Cnt;
352 
353   if (CodeBufferFill >= ErgLen)
354     CodeBufferFill -= ErgLen;
355   else
356   {
357     if (fseek(PrgFile, -(ErgLen - CodeBufferFill), SEEK_CUR) == -1)
358       ChkIO(ErrNum_FileWriteError);
359     CodeBufferFill = 0;
360   }
361 
362   LenSoFar -= ErgLen;
363 
364   Retracted = True;
365 }
366 
367 /*!------------------------------------------------------------------------
368  * \fn     InsertPadding(unsigned NumBytes, Boolean OnlyReserve)
369  * \brief  insert padding bytes into code
370  * \param  NumBytes # of bytes to add
371  * \param  OnlyReserve write code or only reserve?
372  * ------------------------------------------------------------------------ */
373 
InsertPadding(unsigned NumBytes,Boolean OnlyReserve)374 void InsertPadding(unsigned NumBytes, Boolean OnlyReserve)
375 {
376   Boolean SaveDontPrint = DontPrint;
377   LargeWord OldValue = EProgCounter();
378 
379   /* write/reserve code */
380 
381   SetMaxCodeLen(NumBytes);
382   DontPrint = OnlyReserve;
383   memset(BAsmCode, 0, CodeLen = NumBytes);
384   WriteCode();
385   MakeList("<padding>");
386 
387   /* fix up possible label value so it points to the actual code */
388 
389   LabelModify(OldValue, EProgCounter());
390 
391   CodeLen = 0;
392   DontPrint = SaveDontPrint;
393 }
394 
asmcode_init(void)395 void asmcode_init(void)
396 {
397   PatchList = PatchLast = NULL;
398   ExportList = ExportLast = NULL;
399   CodeBuffer = (Byte*) malloc(sizeof(Byte) * (CodeBufferSize + 1));
400 }
401