Blame |
Last modification |
View Log
| Download
| RSS feed
| ?url?
/* asmcode.c */
/*****************************************************************************/
/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* */
/* AS-Portierung */
/* */
/* Verwaltung der Code-Datei */
/* */
/*****************************************************************************/
#include "stdinc.h"
#include <string.h>
#include "version.h"
#include "be_le.h"
#include "chunks.h"
#include "as.h"
#include "asmdef.h"
#include "errmsg.h"
#include "strutil.h"
#include "asmsub.h"
#include "asmpars.h"
#include "asmrelocs.h"
#include "asmlist.h"
#include "asmlabel.h"
#include "asmcode.h"
#define CodeBufferSize 512
static Word LenSoFar
;
static LongInt RecPos
, LenPos
;
static Boolean ThisRel
;
static Word CodeBufferFill
;
static Byte
*CodeBuffer
;
PPatchEntry PatchList
, PatchLast
;
PExportEntry ExportList
, ExportLast
;
LongInt SectSymbolCounter
;
String SectSymbolName
;
static void FlushBuffer
(void)
{
if (CodeBufferFill
> 0)
{
if (fwrite(CodeBuffer
, 1, CodeBufferFill
, PrgFile
) != CodeBufferFill
)
ChkIO
(ErrNum_FileWriteError
);
CodeBufferFill
= 0;
}
}
void DreheCodes
(void)
{
int z
;
LongInt l
= CodeLen
* Granularity
();
switch (ActListGran
)
{
case 2:
for (z
= 0; z
< l
>> 1; z
++)
WAsmCode
[z
] = ((WAsmCode
[z
] & 0xff) << 8) + ((WAsmCode
[z
] & 0xff00) >> 8);
break;
case 4:
for (z
= 0; z
< l
>> 2; z
++)
{
LongWord Dest
;
int z2
;
for (z2
= 0, Dest
= 0; z2
< 4; z2
++)
{
Dest
= (Dest
<< 8) | (DAsmCode
[z
] & 0xff);
DAsmCode
[z
] >>= 8;
}
DAsmCode
[z
] = Dest
;
}
break;
}
}
static void WrPatches
(void)
{
LongWord Cnt
, ExportCnt
, StrLen
;
Byte T8
;
if (PatchList
|| ExportList
)
{
/* find out length of string field */
Cnt
= StrLen
= 0;
for (PatchLast
= PatchList
; PatchLast
; PatchLast
= PatchLast
->Next
)
{
Cnt
++;
StrLen
+= (PatchLast
->len
= strlen(PatchLast
->Ref
) + 1);
}
ExportCnt
= 0;
for (ExportLast
= ExportList
; ExportLast
; ExportLast
= ExportLast
->Next
)
{
ExportCnt
++;
StrLen
+= (ExportLast
->len
= strlen(ExportLast
->Name
) + 1);
}
/* write header */
T8
= FileHeaderRelocInfo
;
if (fwrite(&T8
, 1, 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
if (!Write4
(PrgFile
, &Cnt
)) ChkIO
(ErrNum_FileWriteError
);
if (!Write4
(PrgFile
, &ExportCnt
)) ChkIO
(ErrNum_FileWriteError
);
if (!Write4
(PrgFile
, &StrLen
)) ChkIO
(ErrNum_FileWriteError
);
/* write patch entries */
StrLen
= 0;
for (PatchLast
= PatchList
; PatchLast
; PatchLast
= PatchLast
->Next
)
{
if (!Write8
(PrgFile
, &(PatchLast
->Address
))) ChkIO
(ErrNum_FileWriteError
);
if (!Write4
(PrgFile
, &StrLen
)) ChkIO
(ErrNum_FileWriteError
);
if (!Write4
(PrgFile
, &(PatchLast
->RelocType
))) ChkIO
(ErrNum_FileWriteError
);
StrLen
+= PatchLast
->len
;
}
/* write export entries */
for (ExportLast
= ExportList
; ExportLast
; ExportLast
= ExportLast
->Next
)
{
if (!Write4
(PrgFile
, &StrLen
)) ChkIO
(ErrNum_FileWriteError
);
if (!Write4
(PrgFile
, &(ExportLast
->Flags
))) ChkIO
(ErrNum_FileWriteError
);
if (!Write8
(PrgFile
, &(ExportLast
->Value
))) ChkIO
(ErrNum_FileWriteError
);
StrLen
+= ExportLast
->len
;
}
/* write string table, free structures */
while (PatchList
)
{
PatchLast
= PatchList
;
if (fwrite(PatchLast
->Ref
, 1, PatchLast
->len
, PrgFile
) != PatchLast
->len
) ChkIO
(ErrNum_FileWriteError
);
free(PatchLast
->Ref
);
PatchList
= PatchLast
->Next
;
free(PatchLast
);
}
PatchLast
= NULL
;
while (ExportList
)
{
ExportLast
= ExportList
;
if (fwrite(ExportLast
->Name
, 1, ExportLast
->len
, PrgFile
) != ExportLast
->len
) ChkIO
(ErrNum_FileWriteError
);
free(ExportLast
->Name
);
ExportList
= ExportLast
->Next
;
free(ExportLast
);
}
ExportLast
= NULL
;
}
}
/*--- neuen Record in Codedatei anlegen. War der bisherige leer, so wird ---
---- dieser ueberschrieben. ------------------------------------------------*/
static void WrRecHeader
(void)
{
Byte b
;
/* assume simple record without relocation info */
ThisRel
= RelSegs
;
b
= ThisRel
? FileHeaderRelocRec
: FileHeaderDataRec
;
if (fwrite(&b
, 1, 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
if (fwrite(&HeaderID
, 1, 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
b
= ActPC
; if (fwrite(&b
, 1, 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
b
= Grans
[ActPC
]; if (fwrite(&b
, 1, 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
fflush(PrgFile
);
}
void NewRecord
(LargeWord NStart
)
{
LongInt h
;
LongWord PC
;
Byte Header
;
/* flush remaining code in buffer */
FlushBuffer
();
/* zero length record which may be deleted ? */
/* do not write out patches at this place - they
will be merged with the next record. */
if (LenSoFar
== 0)
{
if (fseek(PrgFile
, RecPos
, SEEK_SET
) != 0) ChkIO
(ErrNum_FileReadError
);
WrRecHeader
();
h
= NStart
;
if (!Write4
(PrgFile
, &h
)) ChkIO
(ErrNum_FileWriteError
);
LenPos
= ftell(PrgFile
);
if (!Write2
(PrgFile
, &LenSoFar
)) ChkIO
(ErrNum_FileWriteError
);
}
/* otherwise full record */
else
{
/* store current position (=end of file) */
h
= ftell(PrgFile
);
/* do we have reloc. info? - then change record type */
if (PatchList
|| ExportList
)
{
fflush(PrgFile
);
if (fseek(PrgFile
, RecPos
, SEEK_SET
) != 0) ChkIO
(ErrNum_FileReadError
);
Header
= ThisRel
? FileHeaderRRelocRec
: FileHeaderRDataRec
;
if (fwrite(&Header
, 1, 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
}
/* fill in length of record */
fflush(PrgFile
);
if (fseek(PrgFile
, LenPos
, SEEK_SET
) != 0) ChkIO
(ErrNum_FileReadError
);
if (!Write2
(PrgFile
, &LenSoFar
)) ChkIO
(ErrNum_FileWriteError
);
/* go back to end of file */
if (fseek(PrgFile
, h
, SEEK_SET
) != 0) ChkIO
(ErrNum_FileReadError
);
/* write out reloc info */
WrPatches
();
/* store begin of new code record */
RecPos
= ftell(PrgFile
);
LenSoFar
= 0;
WrRecHeader
();
ThisRel
= RelSegs
;
PC
= NStart
;
if (!Write4
(PrgFile
, &PC
)) ChkIO
(ErrNum_FileWriteError
);
LenPos
= ftell(PrgFile
);
if (!Write2
(PrgFile
, &LenSoFar
)) ChkIO
(ErrNum_FileWriteError
);
}
#if 0
/* put in the hidden symbol for the relocatable segment ? */
if ((RelSegs
) && (strcmp(CurrFileName
, "INTERNAL")))
{
as_snprintf
(SectSymbolName
, sizeof(SectSymbolName
), "__%s_%d",
NamePart
(CurrFileName
), (int)(SectSymbolCounter
++));
AddExport
(SectSymbolName
, ProgCounter
());
}
#endif
}
/*--- Codedatei eroeffnen --------------------------------------------------*/
void OpenFile
(void)
{
Word h
;
errno
= 0;
PrgFile
= fopen(OutName
, OPENWRMODE
);
if (!PrgFile
)
ChkXIO
(ErrNum_OpeningFile
, OutName
);
errno
= 0;
h
= FileMagic
;
if (!Write2
(PrgFile
,&h
)) ChkIO
(ErrNum_FileWriteError
);
CodeBufferFill
= 0;
RecPos
= ftell(PrgFile
);
LenSoFar
= 0;
NewRecord
(PCs
[ActPC
]);
}
/*---- Codedatei schliessen -------------------------------------------------*/
void CloseFile
(void)
{
Byte Head
;
String h
;
LongWord Adr
;
as_snprintf
(h
, sizeof(h
), "AS %s/%s-%s", Version
, ARCHPRNAME
, ARCHSYSNAME
);
NewRecord
(PCs
[ActPC
]);
fseek(PrgFile
, RecPos
, SEEK_SET
);
if (StartAdrPresent
)
{
Head
= FileHeaderStartAdr
;
if (fwrite(&Head
,sizeof(Head
), 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
Adr
= StartAdr
;
if (!Write4
(PrgFile
,&Adr
)) ChkIO
(ErrNum_FileWriteError
);
}
Head
= FileHeaderEnd
;
if (fwrite(&Head
,sizeof(Head
), 1, PrgFile
) != 1) ChkIO
(ErrNum_FileWriteError
);
if (fwrite(h
, 1, strlen(h
), PrgFile
) != strlen(h
)) ChkIO
(ErrNum_FileWriteError
);
fclose(PrgFile
);
if (Magic
)
unlink
(OutName
);
}
/*--- erzeugten Code einer Zeile in Datei ablegen ---------------------------*/
void WriteBytes
(void)
{
Word ErgLen
;
if (CodeLen
== 0)
return;
ErgLen
= CodeLen
* Granularity
();
if ((TurnWords
!= 0) != (HostBigEndian
!= 0))
DreheCodes
();
if (((LongInt
)LenSoFar
) + ((LongInt
)ErgLen
) > 0xffff)
NewRecord
(PCs
[ActPC
]);
if (CodeBufferFill
+ ErgLen
< CodeBufferSize
)
{
memcpy(CodeBuffer
+ CodeBufferFill
, BAsmCode
, ErgLen
);
CodeBufferFill
+= ErgLen
;
}
else
{
FlushBuffer
();
if (ErgLen
< CodeBufferSize
)
{
memcpy(CodeBuffer
, BAsmCode
, ErgLen
);
CodeBufferFill
= ErgLen
;
}
else if (fwrite(BAsmCode
, 1, ErgLen
, PrgFile
) != ErgLen
)
ChkIO
(ErrNum_FileWriteError
);
}
LenSoFar
+= ErgLen
;
if ((TurnWords
!= 0) != (HostBigEndian
!= 0))
DreheCodes
();
}
void RetractWords
(Word Cnt
)
{
Word ErgLen
;
ErgLen
= Cnt
* Granularity
();
if (LenSoFar
< ErgLen
)
{
WrError
(ErrNum_ParNotPossible
);
return;
}
if (MakeUseList
)
DeleteChunk
(SegChunks
+ ActPC
, ProgCounter
() - Cnt
, Cnt
);
PCs
[ActPC
] -= Cnt
;
if (CodeBufferFill
>= ErgLen
)
CodeBufferFill
-= ErgLen
;
else
{
if (fseek(PrgFile
, -(ErgLen
- CodeBufferFill
), SEEK_CUR
) == -1)
ChkIO
(ErrNum_FileWriteError
);
CodeBufferFill
= 0;
}
LenSoFar
-= ErgLen
;
Retracted
= True
;
}
/*!------------------------------------------------------------------------
* \fn InsertPadding(unsigned NumBytes, Boolean OnlyReserve)
* \brief insert padding bytes into code
* \param NumBytes # of bytes to add
* \param OnlyReserve write code or only reserve?
* ------------------------------------------------------------------------ */
void InsertPadding
(unsigned NumBytes
, Boolean OnlyReserve
)
{
Boolean SaveDontPrint
= DontPrint
;
LargeWord OldValue
= EProgCounter
();
/* write/reserve code */
SetMaxCodeLen
(NumBytes
);
DontPrint
= OnlyReserve
;
memset(BAsmCode
, 0, CodeLen
= NumBytes
);
WriteCode
();
MakeList
("<padding>");
/* fix up possible label value so it points to the actual code */
LabelModify
(OldValue
, EProgCounter
());
CodeLen
= 0;
DontPrint
= SaveDontPrint
;
}
/*!------------------------------------------------------------------------
* \fn indir_split_pos(const char * p_arg)
* \brief find separator for next component in a (x+y-z..) construct
* \param p_arg (remaining) source argument
* \return split position for next component or NULL if no more split character
* ------------------------------------------------------------------------ */
char *indir_split_pos
(const char *p_arg
)
{
char *p_split_pos
= QuotMultPos
(p_arg
, "+-");
/* Sequence of up to three +/- has special meaning for local symbols: */
if (p_split_pos
== p_arg
)
{
int z
;
Boolean same
= True
;
for (z
= 1; p_split_pos
[z
] && (z
< LOCSYMSIGHT
); z
++)
if (p_split_pos
[z
] != p_split_pos
[0])
{
same
= False
;
break;
}
if (!p_split_pos
[z
] && same
)
p_split_pos
= NULL
;
}
return p_split_pos
;
}
void asmcode_init
(void)
{
PatchList
= PatchLast
= NULL
;
ExportList
= ExportLast
= NULL
;
CodeBuffer
= (Byte
*) malloc(sizeof(Byte
) * (CodeBufferSize
+ 1));
}