123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935 |
- /* fix_m68k.c: Routines for M68000 code fixup
- Copyright (C) 2003 Sebastian Reichelt
- Copyright (C) 2003-2007 Kevin Kofler
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
- #include "fix_m68k.h"
- #include "m68k.h"
- #include "fix_tios.h"
- #include "fix_emu.h"
- #include "cutrange.h"
- #include "../manip.h"
- #include <stdlib.h>
- // Apply generic code fixes and optimizations to a section.
- void M68kFixCode (SECTION *Section)
- {
- M68kFixCodePreMerge (Section, NULL, 0);
- }
- // Fix and optionally optimize code executable on the M68k processor family,
- // for two sections which are to be merged.
- // Src may be NULL.
- // If DestSize is nonzero, it specifies a fixed size for the destination
- // section, which will not change even when cutting ranges from it.
- void M68kFixCodePreMerge (SECTION *Dest, SECTION *Src, SIZE DestSize)
- {
- if (Dest->Code && (!(Dest->Frozen)) && (!(Dest->Parent->Frozen)))
- {
- OPTIMIZE_INFO *OptimizeInfo = Dest->Parent->OptimizeInfo;
- SIZE OrigSize = Dest->Size;
-
- RELOC *Reloc, *NextReloc;
-
- // For each reloc...
- for (Reloc = (DestSize ? GetFirst (Dest->Relocs) : GetLast (Dest->Relocs)); Reloc; Reloc = NextReloc)
- {
- NextReloc = (DestSize ? GetNext (Reloc) : GetPrev (Reloc));
-
- // Completely ignore builtin relocs. Also ignore relation-relative
- // relocs, since the only relative relocs we can optimize further
- // are branches, and those are never relation-relative.
- // Ignore relocs which are not in code segments.
- if ((!(Reloc->Target.Builtin || Reloc->Relation || Reloc->Unoptimizable)) && IsCodeRange (Dest, Reloc->Location, Reloc->Location + Reloc->Size))
- {
- // We can only fix or optimize a reloc whose target we know.
- if (Reloc->Target.Symbol && ((Reloc->Target.Symbol->Parent == Dest) || (Reloc->Target.Symbol->Parent == Src)))
- {
- OFFSET TargetDistance;
- // Get the distance of the target symbol, provided it is in the
- // same section.
- if (Reloc->Target.Symbol->Parent == Dest)
- TargetDistance = GetLocationOffset (Dest, &(Reloc->Target));
- // If it is in the next section, add the section size.
- // This is not 100% correct, since we might pad the section, but
- // currently there is no reason to add padding to code. If we get
- // a slightly wrong distance, we will probably get away with it
- // anyway.
- else
- TargetDistance = (DestSize ? : Dest->Size) + GetLocationOffset (Src, &(Reloc->Target));
- // Add the fixed offset because it needs to be added to the reloc
- // target. Subtract the location of the reloc.
- TargetDistance += Reloc->FixedOffset - Reloc->Location;
-
- // Fix and possibly optimize or remove the reloc.
- M68kFixReloc (Reloc, TargetDistance, OptimizeInfo);
- }
- }
- }
-
- if (Dest->Size < OrigSize)
- FinalizeRangeCutting (Dest);
- }
- }
- // Cut the range between Start and End (not including End) if that is
- // permitted; otherwise fill it with NOPs. Start and End are expected
- // to be at even addresses. It is also assumed that IsBinaryDataRange
- // has been called on the range (without an exception, or with an
- // exception that has since been removed).
- // Returns the number of bytes removed.
- static COUNT M68kCutOrFillRange (SECTION *Section, OFFSET Start, OFFSET End, OPTIMIZE_INFO *OptimizeInfo)
- {
- if (End > Start)
- {
- BOOLEAN SectionEnd = End >= Section->Size;
-
- // Make sure Start is not outside of the section data;
- if (Start < 0)
- Start = 0;
- // Make sure End is not outside of the section data;
- if (SectionEnd)
- End = Section->Size;
-
- // If the range is at the end of the section, shrink the section.
- if (SectionEnd && CanShrinkSection (Section, Start, NULL))
- {
- // Look for a short branch to the end of the section. GNU as
- // does this to simulate long conditional branches.
- BOOLEAN BranchFound = FALSE;
- const I1 *Data = Section->Data;
-
- if (Data)
- {
- SIZE Size = Section->Size;
- OFFSET CurPos;
-
- for (CurPos = Size - 4; (CurPos >= 0) && (CurPos >= Size - 8); CurPos -= 2)
- {
- if (((Data [CurPos + 0] & M68K_Bcc_MASK_0) == M68K_Bcc_S_0) && (Data [CurPos + 1] == Size - (CurPos + 2)))
- {
- BranchFound = TRUE;
- break;
- }
- }
- }
-
- if (!BranchFound)
- {
- // No such branch was found, so we can (hopefully) safely cut
- // the section.
- CutSection (Section, Start);
- return End - Start;
- }
- }
- // If the range is in the middle of the section, try to cut it out.
- else
- {
- if (CanCutRange (Section, Start, End))
- {
- SIZE Length = End - Start;
- OptimizeInfo->CutRangesResult += Length;
-
- if (OptimizeInfo->CutRanges)
- {
- CutRange (Section, Start, End);
- OptimizeInfo->NearAssemblyResult -= Length;
- return Length;
- }
- }
- }
-
- // If we cannot cut the range for some reason, fill it with NOPs.
- {
- I1 *Data = Section->Data;
- if (Data)
- {
- OFFSET CurPos;
- for (CurPos = Start; CurPos + 1 < End; CurPos += 2)
- {
- Data [CurPos + 0] = M68K_NOP_0;
- Data [CurPos + 1] = M68K_NOP_1;
- }
- }
- return 0;
- }
- }
- else
- return 0;
- }
- // Fix and possibly optimize a given relocation entry.
- // TargetDistance is the estimated (signed) distance of the relocation target, including the
- // fixed offset. OptimizeInfo contains information about what to optimize.
- // The reloc may be removed during the process.
- void M68kFixReloc (RELOC *Reloc, OFFSET TargetDistance, OPTIMIZE_INFO *OptimizeInfo)
- {
- SECTION *Section = Reloc->Parent;
- I1 *Data = Section->Data;
- OFFSET RelocLocation = Reloc->Location;
- OFFSET OpcodeLocation;
- I1 *Opcode;
-
- if (!Data)
- return;
-
- if (Reloc->Unoptimizable)
- return;
- // Be careful with relocs at the beginning of the section; they might
- // cause segmentation faults when we try to determine the opcode.
- // Usually, ignore all relocs whose location is less than 2.
- // As a special exception, allow 1-byte relocs with a location of 1.
- if (!((Reloc->Location >= 2) || ((Reloc->Size == 1) && (Reloc->Location == 1))))
- return;
-
- // Optimize a subroutine branch followed by an RTS.
- if (OptimizeInfo->OptimizeReturns)
- {
- OFFSET RelocEnd = RelocLocation + Reloc->Size;
- OFFSET RTSEnd = RelocEnd + 2;
-
- if ((RTSEnd <= Section->Size) && (Data [RelocEnd + 0] == M68K_RTS_0) && (Data [RelocEnd + 1] == M68K_RTS_1))
- {
- OFFSET OpcodeLocation;
- I1 *Opcode;
- BOOLEAN Optimized = FALSE;
-
- if (Reloc->Relative)
- {
- switch (Reloc->Size)
- {
- // Optimize 1-byte relative relocs.
- case 1:
- OpcodeLocation = RelocLocation - 1;
- Opcode = Data + OpcodeLocation;
-
- // Check if the reloc belongs to a BSR.S, and that there
- // is nothing in our way.
- if ((Opcode [0] == M68K_BSR_S_0) && (IsBinaryDataRange (Section, OpcodeLocation, RTSEnd, Reloc)))
- {
- // Optimize it into a BRA.S.
- Opcode [0] = M68K_BRA_S_0;
- Optimized = TRUE;
- }
-
- break;
-
- // Optimize 2-byte relative relocs.
- case 2:
- OpcodeLocation = RelocLocation - 2;
- Opcode = Data + OpcodeLocation;
-
- // Check if the reloc belongs to a BSR.W, and that there
- // is nothing in our way.
- if ((Opcode [0] == M68K_BSR_W_0) && (Opcode [1] == M68K_BSR_W_1) && (IsBinaryDataRange (Section, OpcodeLocation, RTSEnd, Reloc)))
- {
- // Optimize it into a JMP.
- Opcode [0] = M68K_BRA_W_0;
- Opcode [1] = M68K_BRA_W_1;
- Optimized = TRUE;
- }
-
- break;
- }
- }
- else
- {
- // Optimize 4-byte absolute relocs.
- if (Reloc->Size == 4)
- {
- OpcodeLocation = RelocLocation - 2;
- Opcode = Data + OpcodeLocation;
-
- // Check if the reloc belongs to a JSR, and that there is
- // nothing in our way.
- if ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1) && (IsBinaryDataRange (Section, OpcodeLocation, RTSEnd, Reloc)))
- {
- // Optimize it into a JMP.
- Opcode [0] = M68K_JMP_0;
- Opcode [1] = M68K_JMP_1;
- Optimized = TRUE;
- }
- }
- }
-
- // Remove the RTS.
- if (Optimized)
- TargetDistance -= M68kCutOrFillRange (Section, RelocEnd, RTSEnd, OptimizeInfo);
- }
- }
-
- // Only branch fixes and optimizations make sense for relative relocs.
- if (Reloc->Relative)
- {
- // Check if it is a 1-byte relative reloc at the end of the
- // section, pointing to the next instruction. This means that
- // the value will probably be 0, which is invalid for 1-byte
- // branches.
- if ((Reloc->Size == 1) && (TargetDistance == 0))
- {
- OpcodeLocation = RelocLocation - 1;
- Opcode = Data + OpcodeLocation;
-
- // Check whether it belongs to a branch. If it does, it
- // is invalid.
- if (((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_S_0) && (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 2, Reloc)))
- {
- // If it is a BSR.S, removing it would modify the
- // semantics. Instead, insert a NOP at the end of the
- // section (if this is really the end of the section).
- if (Opcode [0] == M68K_BSR_S_0)
- {
- if (OpcodeLocation + 2 == Section->Size)
- {
- // Allocate two bytes at the end of the section.
- I1 *Space = AllocateSpaceInSection (Section, 2);
-
- if (Space)
- {
- Space [0] = M68K_NOP_0;
- Space [1] = M68K_NOP_1;
- }
- }
- }
- else
- {
- // Delete the reloc.
- FreeReloc (Reloc);
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation, OpcodeLocation + 2, OptimizeInfo);
-
- // Since the reloc has been removed, return from the function.
- return;
- }
- }
- }
- else if (OptimizeInfo->OptimizeBranches && (Reloc->Size == 2))
- {
- OpcodeLocation = RelocLocation - 2;
- Opcode = Data + OpcodeLocation;
-
- // Check whether the reloc belongs to a branch.
- if (((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_W_0) && (Opcode [1] == M68K_Bcc_W_1) && (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 4, Reloc)))
- {
- // Check whether it can be removed.
- if ((TargetDistance == 2) && (Opcode [0] != M68K_BSR_W_0))
- {
- // Delete the reloc.
- FreeReloc (Reloc);
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation, OpcodeLocation + 4, OptimizeInfo);
-
- // Since the reloc has been removed, return from the function.
- return;
- }
- // Check whether it is near enough for a Bcc.S.
- else if ((TargetDistance != 2) && (M68K_REL_OK (TargetDistance, 1)))
- {
- // Optimize it into a Bcc.S.
- Opcode [0] = M68K_Bcc_S_0 | (Data [OpcodeLocation] & (~M68K_Bcc_MASK_0));
- Opcode [1] = 0;
- // Change the reloc to 1-byte relative.
- Reloc->Size = 1;
- // Adjust the location.
- Reloc->Location--;
- RelocLocation--;
- // Adjust the offset. A short branch always
- // uses the next instruction as a reference.
- Reloc->FixedOffset--;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 2, OpcodeLocation + 4, OptimizeInfo);
- }
- }
- }
- }
- // Other than that, only change 4-byte absolute relocs.
- else if (Reloc->Size == 4)
- {
- // Most opcodes are two bytes long, and the reloc follows
- // immediately.
- OpcodeLocation = RelocLocation - 2;
-
- // Safety check before accessing the section data.
- if (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 6, Reloc))
- {
- Opcode = Data + OpcodeLocation;
-
- {
- // *** Branch Optimization ***
-
- // Try to optimize a 4-byte absolute branch into a 2-byte or 1-byte
- // relative one.
- // Check whether the reloc belongs to a branch.
- BOOLEAN IsJMP = ((Opcode [0] == M68K_JMP_0) && (Opcode [1] == M68K_JMP_1));
- BOOLEAN IsJSR = ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1));
-
- if ((IsJMP || IsJSR))
- {
- // Check whether it can be removed.
- if (OptimizeInfo->OptimizeBranches && (TargetDistance == 4) && IsJMP)
- {
- // Delete the reloc.
- FreeReloc (Reloc);
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation, OpcodeLocation + 6, OptimizeInfo);
-
- OptimizeInfo->OptimizeBranchesResult++;
- }
- // Check whether it is near enough for a BRA.S or BSR.S.
- else if (OptimizeInfo->OptimizeBranches && (TargetDistance != 4) && (M68K_REL_OK (TargetDistance, 1)))
- {
- // Optimize it into a BRA.S or BSR.S.
- Opcode [0] = (IsJSR ? M68K_BSR_S_0 : M68K_BRA_S_0);
- Opcode [1] = 0;
- // Change the reloc to 1-byte relative.
- Reloc->Relative = TRUE;
- Reloc->Size = 1;
- // Adjust the location.
- Reloc->Location--;
- // Adjust the offset. A short branch always
- // uses the next instruction as a reference.
- Reloc->FixedOffset--;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 2, OpcodeLocation + 6, OptimizeInfo);
-
- OptimizeInfo->OptimizeBranchesResult++;
- }
- // Treat it as a normal absolute to relative optimization.
- else
- {
- BOOLEAN BranchOptimized = FALSE;
-
- // Check if the target is near enough for a BRA/BSR.
- if (M68K_REL_OK (TargetDistance, 2))
- {
- OptimizeInfo->OptimizeBranchesResult++;
- if (OptimizeInfo->NearAssemblyResult >= 0)
- OptimizeInfo->NearAssemblyResult += 2;
-
- if (OptimizeInfo->OptimizeBranches)
- {
- // Optimize it into a BRA.W or BSR.W.
- Opcode [0] = (IsJSR ? M68K_BSR_W_0 : M68K_BRA_W_0);
- Opcode [1] = (IsJSR ? M68K_BSR_W_1 : M68K_BRA_W_1);
- // Change the reloc to 2-byte relative.
- Reloc->Relative = TRUE;
- Reloc->Size = 2;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
-
- // Do not try to do anything else with this branch.
- BranchOptimized = TRUE;
- }
- }
- else
- {
- // The target is not near enough. This means that near
- // assembly is not possible.
- OptimizeInfo->NearAssemblyResult = -1;
- }
-
- if (!BranchOptimized)
- {
- // Optimize F-Line jumps if desired.
- OptimizeInfo->UseFLineJumpsResult++;
- if (OptimizeInfo->Use4ByteFLineJumps)
- M68kEmuMakeFLineJump (Reloc, Opcode, IsJSR);
- else if (OptimizeInfo->UseFLineJumps)
- M68kTIOSMakeFLineJump (Reloc, Opcode, IsJSR);
- else
- return;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, Reloc->Location + Reloc->Size, OpcodeLocation + 6, OptimizeInfo);
- }
- }
- }
- // Not a branch.
- else
- {
- BOOLEAN Optimized = FALSE;
-
- // Check if the target is near enough.
- if (M68K_REL_OK (TargetDistance, 2))
- {
- // *** Move Optimization ***
-
- // Optimize LEA(.L) var.L,reg into
- // LEA(.L) var.W(%PC),reg.
- if ((((Opcode [0] & M68K_LEA_ABS_MASK_0) == M68K_LEA_ABS_0) && ((Opcode [1] & M68K_LEA_ABS_MASK_1) == M68K_LEA_ABS_1))
- // Optimize PEA(.L) var.L into PEA(.L) var.W(%PC).
- || ((Opcode [0] == M68K_PEA_ABS_0) && (Opcode [1] == M68K_PEA_ABS_1))
- // Optimize MOVE.x var.L,reg/(reg)/(reg)+ into
- // MOVE.x var.W(%PC),reg/(reg)/(reg)+.
- || (((Opcode [0] & M68K_MOVE_ABS_REG_MASK_0) == M68K_MOVE_ABS_REG_0) && ((Opcode [1] & M68K_MOVE_ABS_REG_MASK_1) == M68K_MOVE_ABS_REG_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_REG_INV_0_MASK_0) == M68K_MOVE_ABS_REG_INV_0_0))
- && (!(((Opcode [0] & M68K_MOVE_ABS_REG_INV_1_MASK_0) == M68K_MOVE_ABS_REG_INV_1_0) && ((Opcode [1] & M68K_MOVE_ABS_REG_INV_1_MASK_1) == M68K_MOVE_ABS_REG_INV_1_1))))
- // Optimize MOVE.x var.L,-(reg) into
- // MOVE.x var.W(%PC),-(reg).
- || (((Opcode [0] & M68K_MOVE_ABS_PREDEC_MASK_0) == M68K_MOVE_ABS_PREDEC_0) && ((Opcode [1] & M68K_MOVE_ABS_PREDEC_MASK_1) == M68K_MOVE_ABS_PREDEC_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_PREDEC_INV_0_MASK_0) == M68K_MOVE_ABS_PREDEC_INV_0_0))))
- {
- OptimizeInfo->OptimizeMovesResult++;
- if (OptimizeInfo->NearAssemblyResult >= 0)
- OptimizeInfo->NearAssemblyResult += 2;
-
- if (OptimizeInfo->OptimizeMoves)
- {
- // Turn the opcode into a pc-relative one.
- M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
-
- // Do everything else later.
- Optimized = TRUE;
- }
- }
-
- // *** Test Optimization ***
-
- // Optimize CMP.x var.L,reg into CMP.x var.W(%PC),reg.
- else if ((((Opcode [0] & M68K_CMP_ABS_REG_MASK_0) == M68K_CMP_ABS_REG_0) && ((Opcode [1] & M68K_CMP_ABS_REG_MASK_1) == M68K_CMP_ABS_REG_1)
- && (!((Opcode [1] & M68K_CMP_ABS_REG_INV_0_MASK_1) == M68K_CMP_ABS_REG_INV_0_1)))
- // Optimize BTST reg,var.L into BTST reg,var.W(%PC).
- || (((Opcode [0] & M68K_BTST_REG_ABS_MASK_0) == M68K_BTST_REG_ABS_0) && ((Opcode [1] & M68K_BTST_REG_ABS_MASK_1) == M68K_BTST_REG_ABS_1)))
- {
- OptimizeInfo->OptimizeTestsResult++;
- if (OptimizeInfo->NearAssemblyResult >= 0)
- OptimizeInfo->NearAssemblyResult += 2;
-
- if (OptimizeInfo->OptimizeTests)
- {
- // Turn the opcode into a pc-relative one.
- M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
-
- // Do everything else later.
- Optimized = TRUE;
- }
- }
-
- // *** Calculation Optimization ***
-
- // Optimize ADD/SUB.x var.L,reg into
- // ADD/SUB.x var.W(%PC),reg.
- else if ((((Opcode [0] & M68K_ADDSUB_ABS_REG_0_MASK_0) == M68K_ADDSUB_ABS_REG_0_0) && ((Opcode [1] & M68K_ADDSUB_ABS_REG_0_MASK_1) == M68K_ADDSUB_ABS_REG_0_1))
- || (((Opcode [0] & M68K_ADDSUB_ABS_REG_1_MASK_0) == M68K_ADDSUB_ABS_REG_1_0) && ((Opcode [1] & M68K_ADDSUB_ABS_REG_1_MASK_1) == M68K_ADDSUB_ABS_REG_1_1))
- // Optimize MUL/DIV.x var.L,reg into
- // MUL/DIV.x var.W(%PC),reg.
- || (((Opcode [0] & M68K_MULDIV_ABS_REG_MASK_0) == M68K_MULDIV_ABS_REG_0) && ((Opcode [1] & M68K_MULDIV_ABS_REG_MASK_1) == M68K_MULDIV_ABS_REG_1))
- // Optimize AND/OR.x var.L,reg into
- // AND/OR.x var.W(%PC),reg.
- || (((Opcode [0] & M68K_ANDOR_ABS_REG_MASK_0) == M68K_ANDOR_ABS_REG_0) && ((Opcode [1] & M68K_ANDOR_ABS_REG_MASK_1) == M68K_ANDOR_ABS_REG_1)))
- {
- OptimizeInfo->OptimizeCalcsResult++;
- if (OptimizeInfo->NearAssemblyResult >= 0)
- OptimizeInfo->NearAssemblyResult += 2;
-
- if (OptimizeInfo->OptimizeCalcs)
- {
- // Turn the opcode into a pc-relative one.
- M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
-
- // Do everything else later.
- Optimized = TRUE;
- }
- }
- }
-
- if (Optimized)
- {
- // Change the reloc to 2-byte relative.
- Reloc->Relative = TRUE;
- Reloc->Size = 2;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
- }
- else
- {
- // Check if the target is near enough.
- if (M68K_REL_OK (TargetDistance, 2))
- {
- if (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
- {
- // Optimize MOVE.x var.L,ofs(reg) into
- // MOVE.x var.W(%PC),ofs(reg)
- // We cannot handle this above because of the
- // offset, which comes after the reloc.
- if (((Opcode [0] & M68K_MOVE_ABS_OFSREG_MASK_0) == M68K_MOVE_ABS_OFSREG_0) && ((Opcode [1] & M68K_MOVE_ABS_OFSREG_MASK_1) == M68K_MOVE_ABS_OFSREG_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_OFSREG_INV_0_MASK_0) == M68K_MOVE_ABS_OFSREG_INV_0_0)))
- {
- OptimizeInfo->OptimizeMovesResult++;
- if (OptimizeInfo->NearAssemblyResult >= 0)
- OptimizeInfo->NearAssemblyResult += 2;
-
- if (OptimizeInfo->OptimizeMoves)
- {
- // Turn the opcode into a pc-relative one.
- M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
-
- // Move the offset to the correct place.
- Opcode [4] = Opcode [6];
- Opcode [5] = Opcode [7];
-
- // Change the reloc to 2-byte relative.
- Reloc->Relative = TRUE;
- Reloc->Size = 2;
- Optimized = TRUE;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
- }
- }
- }
-
- {
- OpcodeLocation = RelocLocation - 4;
- Opcode = Data + OpcodeLocation;
-
- if (!Optimized && IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
- {
- // Optimize MOVEM.x var.L,regs into
- // MOVEM var.W(%PC),regs.
- if (((Opcode [0] & M68K_MOVEM_ABS_REGS_MASK_0) == M68K_MOVEM_ABS_REGS_0) && ((Opcode [1] & M68K_MOVEM_ABS_REGS_MASK_1) == M68K_MOVEM_ABS_REGS_1))
- {
- OptimizeInfo->OptimizeMovesResult++;
- if (OptimizeInfo->NearAssemblyResult >= 0)
- OptimizeInfo->NearAssemblyResult += 2;
-
- if (OptimizeInfo->OptimizeMoves)
- {
- // Turn the opcode into a pc-relative one.
- M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
-
- // Change the reloc to 2-byte relative.
- Reloc->Relative = TRUE;
- Reloc->Size = 2;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
- }
- }
- // Optimize BTST #num,var.L into
- // BTST #num,var.W(%PC).
- else if ((Opcode [0] == M68K_BTST_IMM_ABS_0) && (Opcode [1] == M68K_BTST_IMM_ABS_1) && (Opcode [2] == M68K_BTST_IMM_ABS_2))
- {
- OptimizeInfo->OptimizeTestsResult++;
- if (OptimizeInfo->NearAssemblyResult >= 0)
- OptimizeInfo->NearAssemblyResult += 2;
-
- if (OptimizeInfo->OptimizeTests)
- {
- // Turn the opcode into a pc-relative one.
- M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
-
- // Change the reloc to 2-byte relative.
- Reloc->Relative = TRUE;
- Reloc->Size = 2;
-
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
- }
- }
- }
- }
- }
- else
- {
- // The target is not near enough. This means that near
- // assembly is not possible.
- OptimizeInfo->NearAssemblyResult = -1;
- }
- }
- }
- }
- }
- }
- }
- // Checks if a specific reloc might be optimizable. This is currently
- // limited to 4-bytes absolute relocs because that is the only case
- // this is needed for.
- BOOLEAN M68kIsRelocOptimizable (const RELOC *Reloc)
- {
- if (Reloc->Unoptimizable) return FALSE;
- if (Reloc->Size == 4 && (!(Reloc->Relative)))
- {
- const SECTION *Section = Reloc->Parent;
-
- // Most opcodes are two bytes long, and the reloc follows
- // immediately.
- OFFSET OpcodeLocation = Reloc->Location - 2;
-
- // Safety check before accessing the section data.
- if (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 6, Reloc))
- {
- const I1 *Opcode = Section->Data + OpcodeLocation;
- // *** Branch Optimization ***
- if (((Opcode [0] == M68K_JMP_0) && (Opcode [1] == M68K_JMP_1))
- || ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1))
- // *** Move Optimization ***
- || (((Opcode [0] & M68K_LEA_ABS_MASK_0) == M68K_LEA_ABS_0) && ((Opcode [1] & M68K_LEA_ABS_MASK_1) == M68K_LEA_ABS_1))
- || ((Opcode [0] == M68K_PEA_ABS_0) && (Opcode [1] == M68K_PEA_ABS_1))
- || (((Opcode [0] & M68K_MOVE_ABS_REG_MASK_0) == M68K_MOVE_ABS_REG_0) && ((Opcode [1] & M68K_MOVE_ABS_REG_MASK_1) == M68K_MOVE_ABS_REG_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_REG_INV_0_MASK_0) == M68K_MOVE_ABS_REG_INV_0_0))
- && (!(((Opcode [0] & M68K_MOVE_ABS_REG_INV_1_MASK_0) == M68K_MOVE_ABS_REG_INV_1_0) && ((Opcode [1] & M68K_MOVE_ABS_REG_INV_1_MASK_1) == M68K_MOVE_ABS_REG_INV_1_1))))
- || (((Opcode [0] & M68K_MOVE_ABS_PREDEC_MASK_0) == M68K_MOVE_ABS_PREDEC_0) && ((Opcode [1] & M68K_MOVE_ABS_PREDEC_MASK_1) == M68K_MOVE_ABS_PREDEC_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_PREDEC_INV_0_MASK_0) == M68K_MOVE_ABS_PREDEC_INV_0_0)))
- || (((Opcode [0] & M68K_MOVE_ABS_OFSREG_MASK_0) == M68K_MOVE_ABS_OFSREG_0) && ((Opcode [1] & M68K_MOVE_ABS_OFSREG_MASK_1) == M68K_MOVE_ABS_OFSREG_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_OFSREG_INV_0_MASK_0) == M68K_MOVE_ABS_OFSREG_INV_0_0)))
- || (((Opcode [0] & M68K_MOVEM_ABS_REGS_MASK_0) == M68K_MOVEM_ABS_REGS_0) && ((Opcode [1] & M68K_MOVEM_ABS_REGS_MASK_1) == M68K_MOVEM_ABS_REGS_1))
- // *** Test Optimization ***
- || (((Opcode [0] & M68K_CMP_ABS_REG_MASK_0) == M68K_CMP_ABS_REG_0) && ((Opcode [1] & M68K_CMP_ABS_REG_MASK_1) == M68K_CMP_ABS_REG_1)
- && (!((Opcode [1] & M68K_CMP_ABS_REG_INV_0_MASK_1) == M68K_CMP_ABS_REG_INV_0_1)))
- || (((Opcode [0] & M68K_BTST_REG_ABS_MASK_0) == M68K_BTST_REG_ABS_0) && ((Opcode [1] & M68K_BTST_REG_ABS_MASK_1) == M68K_BTST_REG_ABS_1))
- || ((Opcode [0] == M68K_BTST_IMM_ABS_0) && (Opcode [1] == M68K_BTST_IMM_ABS_1) && (Opcode [2] == M68K_BTST_IMM_ABS_2))
- // *** Calculation Optimization ***
- || (((Opcode [0] & M68K_ADDSUB_ABS_REG_0_MASK_0) == M68K_ADDSUB_ABS_REG_0_0) && ((Opcode [1] & M68K_ADDSUB_ABS_REG_0_MASK_1) == M68K_ADDSUB_ABS_REG_0_1))
- || (((Opcode [0] & M68K_ADDSUB_ABS_REG_1_MASK_0) == M68K_ADDSUB_ABS_REG_1_0) && ((Opcode [1] & M68K_ADDSUB_ABS_REG_1_MASK_1) == M68K_ADDSUB_ABS_REG_1_1))
- || (((Opcode [0] & M68K_MULDIV_ABS_REG_MASK_0) == M68K_MULDIV_ABS_REG_0) && ((Opcode [1] & M68K_MULDIV_ABS_REG_MASK_1) == M68K_MULDIV_ABS_REG_1))
- || (((Opcode [0] & M68K_ANDOR_ABS_REG_MASK_0) == M68K_ANDOR_ABS_REG_0) && ((Opcode [1] & M68K_ANDOR_ABS_REG_MASK_1) == M68K_ANDOR_ABS_REG_1)))
- return TRUE;
- }
- }
-
- return FALSE;
- }
- // If the section ends with exactly one NOP instruction, remove the NOP.
- void M68kRemoveTrailingNOP (SECTION *Section)
- {
- I1 *Data = Section->Data;
- SIZE Size = Section->Size;
-
- // Validate basic circumstances.
- if (Data && (Size >= 4)
- // Check for NOP in last instruction.
- && (Data [Size - 2] == M68K_NOP_0) && (Data [Size - 1] == M68K_NOP_1) && (IsBinaryDataRange (Section, Size - 2, Size, NULL))
- // Check for NOP in previous instruction (which would mean that we
- // actually want the NOPs to be there).
- && (!((Data [Size - 4] == M68K_NOP_0) && (Data [Size - 3] == M68K_NOP_1)))
- // Check if something prevents us from shrinking the section.
- && (CanShrinkSection (Section, Size - 2, NULL)))
- // Cut the NOP away.
- CutSection (Section, Size - 2);
- }
- // Fix and return the target offset of a reloc.
- // In particular, for 1-byte relative relocs, the target offset is
- // increased by 1, so the the reloc points to the symbol and not to
- // the symbol minus 1.
- OFFSET M68kFixTargetOffset (OFFSET Offset, SIZE RelocSize, BOOLEAN RelocRelative)
- {
- if (RelocRelative && (RelocSize == 1))
- return Offset + 1;
- else
- return Offset;
- }
- #define SHORT_IMPORTANCE 2048
- // Called by M68kGetSectionRelationship; see below.
- static COUNT M68kGetRelocImportance (const RELOC *Reloc, OFFSET Offset)
- {
- SECTION *Section = Reloc->Parent;
-
- if (Reloc->Unoptimizable) return 0;
- // Byte offsets are useful only for jumps or branches, so detect
- // them.
- if (M68K_REL_OK (Offset, 1))
- {
- OFFSET RelocLocation = Reloc->Location;
- OFFSET OpcodeLocation = RelocLocation - 2;
- I1 *Opcode = Section->Data + OpcodeLocation;
- if (Reloc->Size == 4)
- {
- // Check whether the reloc belongs to a branch.
- BOOLEAN IsJMP = ((Opcode [0] == M68K_JMP_0)
- && (Opcode [1] == M68K_JMP_1));
- BOOLEAN IsJSR = ((Opcode [0] == M68K_JSR_0)
- && (Opcode [1] == M68K_JSR_1));
-
- if ((IsJMP || IsJSR)
- && IsBinaryDataRange (Section,
- OpcodeLocation,
- OpcodeLocation + 6, Reloc))
- {
- return ((Offset == 4 && IsJMP) ? SHORT_IMPORTANCE * 2
- : SHORT_IMPORTANCE);
- }
- }
- else if (Reloc->Size == 2)
- {
- // Check whether the reloc belongs to a branch.
- if ((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_W_0
- && Opcode [1] == M68K_Bcc_W_1
- && IsBinaryDataRange (Section,
- OpcodeLocation,
- OpcodeLocation + 4, Reloc))
- {
- return (Offset == 2 && !(Opcode [0] == M68K_BSR_W_0
- && Opcode [1] == M68K_BSR_W_1)) ? SHORT_IMPORTANCE * 2
- : SHORT_IMPORTANCE;
- }
- }
- }
-
- // Everything else is not optimizable.
- return 0;
- }
- // Determines the amount of relationship between the two sections, for the
- // situation that Section2 might be put just behind Section1. A reference
- // that could potentially be short gets 2048 points; a reference that could
- // potentially be removed gets twice as much.
- // The effect is that a section with one potentially short reference can
- // be at most 2048 bytes long for being inserted immediately by reordering,
- // and so on.
- COUNT M68kGetSectionRelationship (const SECTION *Section1, const SECTION *Section2)
- {
- COUNT Result = 0;
-
- const RELOC *Reloc;
- for_each (Reloc, Section1->Relocs)
- {
- const SYMBOL *TargetSymbol = Reloc->Target.Symbol;
- if (TargetSymbol && TargetSymbol->Parent == Section2)
- Result += M68kGetRelocImportance (Reloc, Section1->Size - Reloc->Location + TargetSymbol->Location + Reloc->Target.Offset + Reloc->FixedOffset);
- }
- for_each (Reloc, Section2->Relocs)
- {
- const SYMBOL *TargetSymbol = Reloc->Target.Symbol;
- if (TargetSymbol && TargetSymbol->Parent == Section1)
- Result += M68kGetRelocImportance (Reloc, TargetSymbol->Location + Reloc->Target.Offset + Reloc->FixedOffset - Section1->Size - Reloc->Location);
- }
-
- return Result;
- }
- // Compute an estimate of how important it is to put the section containing this
- // reloc next during local section reordering.
- // Here are the estimates used:
- // 0-byte branches save 6 bytes and 1 reloc and cannot be deferred -> 512 points
- // 2-byte branches save 4 bytes and 1 reloc and can rarely be deferred -> 256
- // PC-relative references save 2 bytes and 1 reloc. They can be deferred based
- // on how far the accumulated distance is. We compute between 0 and 32 points
- // based on the offset, with the formula: (offset^2>>25)+2.
- COUNT M68kComputeRelocGoodness(OFFSET Offset, RELOC *Reloc)
- {
- SECTION *Section = Reloc->Parent;
-
- if (Reloc->Unoptimizable) return 0;
- // Byte offsets are useful only for jumps or branches, so detect
- // them.
- if (M68K_REL_OK (Offset, 1))
- {
- OFFSET RelocLocation = Reloc->Location;
- OFFSET OpcodeLocation = RelocLocation - 2;
- I1 *Opcode = Section->Data + OpcodeLocation;
- if (Reloc->Size == 4)
- {
- // Check whether the reloc belongs to a branch.
- BOOLEAN IsJMP = ((Opcode [0] == M68K_JMP_0)
- && (Opcode [1] == M68K_JMP_1));
- BOOLEAN IsJSR = ((Opcode [0] == M68K_JSR_0)
- && (Opcode [1] == M68K_JSR_1));
-
- if ((IsJMP || IsJSR)
- && IsBinaryDataRange (Section,
- OpcodeLocation,
- OpcodeLocation + 6, Reloc))
- {
- return (Offset == 4 && IsJMP) ? 512 : 256;
- }
- }
- else if (Reloc->Size == 2)
- {
- // Check whether the reloc belongs to a branch.
- if ((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_W_0
- && Opcode [1] == M68K_Bcc_W_1
- && IsBinaryDataRange (Section,
- OpcodeLocation,
- OpcodeLocation + 4, Reloc))
- {
- return (Offset == 2 && !(Opcode [0] == M68K_BSR_W_0
- && Opcode [1] == M68K_BSR_W_1)) ? 512
- : 256;
- }
- }
- }
- // Word offsets are useful everywhere where a PC-relative reference is
- // possible. So look for those places.
- if (M68K_REL_OK (Offset, 2))
- {
- OFFSET RelocLocation = Reloc->Location;
- OFFSET OpcodeLocation = RelocLocation - 2;
- I1 *Opcode = Section->Data + OpcodeLocation;
- // Safety check before accessing the section data.
- if (Reloc->Size == 4 && IsBinaryDataRange (Section, OpcodeLocation,
- OpcodeLocation + 6, Reloc))
- {
- // Check whether the reloc belongs to a branch.
- if (((Opcode [0] == M68K_JMP_0) && (Opcode [1] == M68K_JMP_1))
- || ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1))
- // Optimize LEA(.L) var.L,reg into
- // LEA(.L) var.W(%PC),reg.
- || (((Opcode [0] & M68K_LEA_ABS_MASK_0) == M68K_LEA_ABS_0) && ((Opcode [1] & M68K_LEA_ABS_MASK_1) == M68K_LEA_ABS_1))
- // Optimize PEA(.L) var.L into PEA(.L) var.W(%PC).
- || ((Opcode [0] == M68K_PEA_ABS_0) && (Opcode [1] == M68K_PEA_ABS_1))
- // Optimize MOVE.x var.L,reg/(reg)/(reg)+ into
- // MOVE.x var.W(%PC),reg/(reg)/(reg)+.
- || (((Opcode [0] & M68K_MOVE_ABS_REG_MASK_0) == M68K_MOVE_ABS_REG_0) && ((Opcode [1] & M68K_MOVE_ABS_REG_MASK_1) == M68K_MOVE_ABS_REG_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_REG_INV_0_MASK_0) == M68K_MOVE_ABS_REG_INV_0_0))
- && (!(((Opcode [0] & M68K_MOVE_ABS_REG_INV_1_MASK_0) == M68K_MOVE_ABS_REG_INV_1_0) && ((Opcode [1] & M68K_MOVE_ABS_REG_INV_1_MASK_1) == M68K_MOVE_ABS_REG_INV_1_1))))
- // Optimize MOVE.x var.L,-(reg) into
- // MOVE.x var.W(%PC),-(reg).
- || (((Opcode [0] & M68K_MOVE_ABS_PREDEC_MASK_0) == M68K_MOVE_ABS_PREDEC_0) && ((Opcode [1] & M68K_MOVE_ABS_PREDEC_MASK_1) == M68K_MOVE_ABS_PREDEC_1)
- && (!((Opcode [0] & M68K_MOVE_ABS_PREDEC_INV_0_MASK_0) == M68K_MOVE_ABS_PREDEC_INV_0_0)))
- // Optimize CMP.x var.L,reg into CMP.x var.W(%PC),reg.
- || (((Opcode [0] & M68K_CMP_ABS_REG_MASK_0) == M68K_CMP_ABS_REG_0) && ((Opcode [1] & M68K_CMP_ABS_REG_MASK_1) == M68K_CMP_ABS_REG_1)
- && (!((Opcode [1] & M68K_CMP_ABS_REG_INV_0_MASK_1) == M68K_CMP_ABS_REG_INV_0_1)))
- // Optimize BTST reg,var.L into BTST reg,var.W(%PC).
- || (((Opcode [0] & M68K_BTST_REG_ABS_MASK_0) == M68K_BTST_REG_ABS_0) && ((Opcode [1] & M68K_BTST_REG_ABS_MASK_1) == M68K_BTST_REG_ABS_1))
- // Optimize ADD/SUB.x var.L,reg into
- // ADD/SUB.x var.W(%PC),reg.
- || (((Opcode [0] & M68K_ADDSUB_ABS_REG_0_MASK_0) == M68K_ADDSUB_ABS_REG_0_0) && ((Opcode [1] & M68K_ADDSUB_ABS_REG_0_MASK_1) == M68K_ADDSUB_ABS_REG_0_1))
- || (((Opcode [0] & M68K_ADDSUB_ABS_REG_1_MASK_0) == M68K_ADDSUB_ABS_REG_1_0) && ((Opcode [1] & M68K_ADDSUB_ABS_REG_1_MASK_1) == M68K_ADDSUB_ABS_REG_1_1))
- // Optimize MUL/DIV.x var.L,reg into
- // MUL/DIV.x var.W(%PC),reg.
- || (((Opcode [0] & M68K_MULDIV_ABS_REG_MASK_0) == M68K_MULDIV_ABS_REG_0) && ((Opcode [1] & M68K_MULDIV_ABS_REG_MASK_1) == M68K_MULDIV_ABS_REG_1))
- // Optimize AND/OR.x var.L,reg into
- // AND/OR.x var.W(%PC),reg.
- || (((Opcode [0] & M68K_ANDOR_ABS_REG_MASK_0) == M68K_ANDOR_ABS_REG_0) && ((Opcode [1] & M68K_ANDOR_ABS_REG_MASK_1) == M68K_ANDOR_ABS_REG_1)))
- {
- return ((Offset * Offset) >> 25);
- }
- }
- }
- // Everything else is not optimizable, so ignore it for section reordering.
- return 0;
- }
|