1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120 |
- /* 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>
- #ifdef FLASH_OS_SUPPORT
- static void M68kFixBssAbs16 (RELOC *Reloc, OPTIMIZE_INFO *OptimizeInfo);
- #endif
- // 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);
- }
- #ifdef FLASH_OS_SUPPORT
- // If we are for a flash os program, and the target is a BSS Section.
- if (Dest->Parent->Type == PT_FLASH_OS && Reloc->Target.Symbol
- && Reloc->Target.Symbol->Parent == Reloc->Parent->Parent->BSSSection)
- M68kFixBssAbs16 (Reloc, OptimizeInfo);
- #endif
- }
- }
-
- 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;
- }
- }
- }
- }
- }
- }
- }
- #ifdef FLASH_OS_SUPPORT
- static void M68kFixBssAbs16 (RELOC *Reloc, OPTIMIZE_INFO *OptimizeInfo)
- {
- SECTION *Section = Reloc->Parent;
- I1 *Data = Section->Data;
- OFFSET RelocLocation = Reloc->Location;
- OFFSET OpcodeLocation;
- I1 *Opcode;
- // Return if there is no data, the reloc is not optimizable or if the reloc size is not 4 bytes.
- // If the section doesn't support the cut ranges, it doesn't worth the effort (we don't any reloc to emit).
- if (!Data || Reloc->Unoptimizable || Reloc->Size != 4 || !Section->CanCutRanges)
- return;
- if (!(Reloc->Target.Symbol))
- return;
- // Test is the reloc is optimizable: the absolute address muse be < 2^15
- OpcodeLocation = GetLocationOffset (Reloc->Target.Symbol->Parent, &(Reloc->Target)) + Reloc->FixedOffset;
- OpcodeLocation += (OFFSET) (OptimizeInfo->FlashOSBSSStart);
- if (OpcodeLocation >= 0x7FFF)
- return;
- // 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))
- return;
- Opcode = Data + OpcodeLocation;
- // *** Move Optimization ***
- // Optimize LEA(.L) var.L,reg into LEA(.w) var.W),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->OptimizeMoves)
- {
- // Turn the opcode into an abs16 one.
- M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
- // Change the reloc to 2-byte absolute.
- Reloc->Size = 2;
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
- }
- return;
- }
- // *** Test Optimization ***
- // Optimize CMP.x var.L,reg into CMP.x var.W(%PC),reg.
- 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->OptimizeTests)
- {
- // Turn the opcode into a abs16 one.
- M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
- // Change the reloc to 2-byte absolute.
- Reloc->Size = 2;
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
- }
- return;
- }
- // *** Calculation Optimization ***
- // Optimize ADD/SUB.x var.L,reg into
- // ADD/SUB.x var.W(%PC),reg.
- 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->OptimizeCalcs)
- {
- // Turn the opcode into a abs16 one.
- M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
- // Change the reloc to 2-byte .
- Reloc->Size = 2;
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
- }
- return;
- }
- // Check opcodes of 8 bytes without prefix
- if (!IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
- return;
- // Optimize MOVE.x var.L,ofs(reg) into
- // MOVE.x var.W,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->OptimizeMoves)
- {
- // Turn the opcode into a abs16 one.
- M68K_MAKE_ABS16_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 abs16.
- Reloc->Size = 2;
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
- }
- return;
- }
- // Now Opcode are bigger (8 bytes)
- OpcodeLocation = RelocLocation - 4;
- Opcode = Data + OpcodeLocation;
- if (!IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
- return;
- // Optimize MOVEM.x var.L,regs into
- // MOVEM var.W,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->OptimizeMoves)
- {
- // Turn the opcode into a abs16 one.
- M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
- // Change the reloc to 2-byte relative.
- 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
- 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->OptimizeTests)
- {
- // Turn the opcode into a abs16 one.
- M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
- // Change the reloc to 2-byte absolute.
- Reloc->Size = 2;
- // Cut or fill the gained space.
- M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
- }
- }
- // Nothing can be done
- return;
- }
- #endif
- // 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;
- }
|