fix_m68k.c 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120
  1. /* fix_m68k.c: Routines for M68000 code fixup
  2. Copyright (C) 2003 Sebastian Reichelt
  3. Copyright (C) 2003-2007 Kevin Kofler
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software Foundation,
  14. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  15. #include "fix_m68k.h"
  16. #include "m68k.h"
  17. #include "fix_tios.h"
  18. #include "fix_emu.h"
  19. #include "cutrange.h"
  20. #include "../manip.h"
  21. #include <stdlib.h>
  22. #ifdef FLASH_OS_SUPPORT
  23. static void M68kFixBssAbs16 (RELOC *Reloc, OPTIMIZE_INFO *OptimizeInfo);
  24. #endif
  25. // Apply generic code fixes and optimizations to a section.
  26. void M68kFixCode (SECTION *Section)
  27. {
  28. M68kFixCodePreMerge (Section, NULL, 0);
  29. }
  30. // Fix and optionally optimize code executable on the M68k processor family,
  31. // for two sections which are to be merged.
  32. // Src may be NULL.
  33. // If DestSize is nonzero, it specifies a fixed size for the destination
  34. // section, which will not change even when cutting ranges from it.
  35. void M68kFixCodePreMerge (SECTION *Dest, SECTION *Src, SIZE DestSize)
  36. {
  37. if (Dest->Code && (!(Dest->Frozen)) && (!(Dest->Parent->Frozen)))
  38. {
  39. OPTIMIZE_INFO *OptimizeInfo = Dest->Parent->OptimizeInfo;
  40. SIZE OrigSize = Dest->Size;
  41. RELOC *Reloc, *NextReloc;
  42. // For each reloc...
  43. for (Reloc = (DestSize ? GetFirst (Dest->Relocs) : GetLast (Dest->Relocs)); Reloc; Reloc = NextReloc)
  44. {
  45. NextReloc = (DestSize ? GetNext (Reloc) : GetPrev (Reloc));
  46. // Completely ignore builtin relocs. Also ignore relation-relative
  47. // relocs, since the only relative relocs we can optimize further
  48. // are branches, and those are never relation-relative.
  49. // Ignore relocs which are not in code segments.
  50. if ((!(Reloc->Target.Builtin || Reloc->Relation || Reloc->Unoptimizable)) && IsCodeRange (Dest, Reloc->Location, Reloc->Location + Reloc->Size))
  51. {
  52. // We can only fix or optimize a reloc whose target we know.
  53. if (Reloc->Target.Symbol && ((Reloc->Target.Symbol->Parent == Dest) || (Reloc->Target.Symbol->Parent == Src)))
  54. {
  55. OFFSET TargetDistance;
  56. // Get the distance of the target symbol, provided it is in the
  57. // same section.
  58. if (Reloc->Target.Symbol->Parent == Dest)
  59. TargetDistance = GetLocationOffset (Dest, &(Reloc->Target));
  60. // If it is in the next section, add the section size.
  61. // This is not 100% correct, since we might pad the section, but
  62. // currently there is no reason to add padding to code. If we get
  63. // a slightly wrong distance, we will probably get away with it
  64. // anyway.
  65. else
  66. TargetDistance = (DestSize ? : Dest->Size) + GetLocationOffset (Src, &(Reloc->Target));
  67. // Add the fixed offset because it needs to be added to the reloc
  68. // target. Subtract the location of the reloc.
  69. TargetDistance += Reloc->FixedOffset - Reloc->Location;
  70. // Fix and possibly optimize or remove the reloc.
  71. M68kFixReloc (Reloc, TargetDistance, OptimizeInfo);
  72. }
  73. #ifdef FLASH_OS_SUPPORT
  74. // If we are for a flash os program, and the target is a BSS Section.
  75. if (Dest->Parent->Type == PT_FLASH_OS && Reloc->Target.Symbol
  76. && Reloc->Target.Symbol->Parent == Reloc->Parent->Parent->BSSSection)
  77. M68kFixBssAbs16 (Reloc, OptimizeInfo);
  78. #endif
  79. }
  80. }
  81. if (Dest->Size < OrigSize)
  82. FinalizeRangeCutting (Dest);
  83. }
  84. }
  85. // Cut the range between Start and End (not including End) if that is
  86. // permitted; otherwise fill it with NOPs. Start and End are expected
  87. // to be at even addresses. It is also assumed that IsBinaryDataRange
  88. // has been called on the range (without an exception, or with an
  89. // exception that has since been removed).
  90. // Returns the number of bytes removed.
  91. static COUNT M68kCutOrFillRange (SECTION *Section, OFFSET Start, OFFSET End, OPTIMIZE_INFO *OptimizeInfo)
  92. {
  93. if (End > Start)
  94. {
  95. BOOLEAN SectionEnd = End >= Section->Size;
  96. // Make sure Start is not outside of the section data;
  97. if (Start < 0)
  98. Start = 0;
  99. // Make sure End is not outside of the section data;
  100. if (SectionEnd)
  101. End = Section->Size;
  102. // If the range is at the end of the section, shrink the section.
  103. if (SectionEnd && CanShrinkSection (Section, Start, NULL))
  104. {
  105. // Look for a short branch to the end of the section. GNU as
  106. // does this to simulate long conditional branches.
  107. BOOLEAN BranchFound = FALSE;
  108. const I1 *Data = Section->Data;
  109. if (Data)
  110. {
  111. SIZE Size = Section->Size;
  112. OFFSET CurPos;
  113. for (CurPos = Size - 4; (CurPos >= 0) && (CurPos >= Size - 8); CurPos -= 2)
  114. {
  115. if (((Data [CurPos + 0] & M68K_Bcc_MASK_0) == M68K_Bcc_S_0) && (Data [CurPos + 1] == Size - (CurPos + 2)))
  116. {
  117. BranchFound = TRUE;
  118. break;
  119. }
  120. }
  121. }
  122. if (!BranchFound)
  123. {
  124. // No such branch was found, so we can (hopefully) safely cut
  125. // the section.
  126. CutSection (Section, Start);
  127. return End - Start;
  128. }
  129. }
  130. // If the range is in the middle of the section, try to cut it out.
  131. else
  132. {
  133. if (CanCutRange (Section, Start, End))
  134. {
  135. SIZE Length = End - Start;
  136. OptimizeInfo->CutRangesResult += Length;
  137. if (OptimizeInfo->CutRanges)
  138. {
  139. CutRange (Section, Start, End);
  140. OptimizeInfo->NearAssemblyResult -= Length;
  141. return Length;
  142. }
  143. }
  144. }
  145. // If we cannot cut the range for some reason, fill it with NOPs.
  146. {
  147. I1 *Data = Section->Data;
  148. if (Data)
  149. {
  150. OFFSET CurPos;
  151. for (CurPos = Start; CurPos + 1 < End; CurPos += 2)
  152. {
  153. Data [CurPos + 0] = M68K_NOP_0;
  154. Data [CurPos + 1] = M68K_NOP_1;
  155. }
  156. }
  157. return 0;
  158. }
  159. }
  160. else
  161. return 0;
  162. }
  163. // Fix and possibly optimize a given relocation entry.
  164. // TargetDistance is the estimated (signed) distance of the relocation target, including the
  165. // fixed offset. OptimizeInfo contains information about what to optimize.
  166. // The reloc may be removed during the process.
  167. void M68kFixReloc (RELOC *Reloc, OFFSET TargetDistance, OPTIMIZE_INFO *OptimizeInfo)
  168. {
  169. SECTION *Section = Reloc->Parent;
  170. I1 *Data = Section->Data;
  171. OFFSET RelocLocation = Reloc->Location;
  172. OFFSET OpcodeLocation;
  173. I1 *Opcode;
  174. if (!Data)
  175. return;
  176. if (Reloc->Unoptimizable)
  177. return;
  178. // Be careful with relocs at the beginning of the section; they might
  179. // cause segmentation faults when we try to determine the opcode.
  180. // Usually, ignore all relocs whose location is less than 2.
  181. // As a special exception, allow 1-byte relocs with a location of 1.
  182. if (!((Reloc->Location >= 2) || ((Reloc->Size == 1) && (Reloc->Location == 1))))
  183. return;
  184. // Optimize a subroutine branch followed by an RTS.
  185. if (OptimizeInfo->OptimizeReturns)
  186. {
  187. OFFSET RelocEnd = RelocLocation + Reloc->Size;
  188. OFFSET RTSEnd = RelocEnd + 2;
  189. if ((RTSEnd <= Section->Size) && (Data [RelocEnd + 0] == M68K_RTS_0) && (Data [RelocEnd + 1] == M68K_RTS_1))
  190. {
  191. OFFSET OpcodeLocation;
  192. I1 *Opcode;
  193. BOOLEAN Optimized = FALSE;
  194. if (Reloc->Relative)
  195. {
  196. switch (Reloc->Size)
  197. {
  198. // Optimize 1-byte relative relocs.
  199. case 1:
  200. OpcodeLocation = RelocLocation - 1;
  201. Opcode = Data + OpcodeLocation;
  202. // Check if the reloc belongs to a BSR.S, and that there
  203. // is nothing in our way.
  204. if ((Opcode [0] == M68K_BSR_S_0) && (IsBinaryDataRange (Section, OpcodeLocation, RTSEnd, Reloc)))
  205. {
  206. // Optimize it into a BRA.S.
  207. Opcode [0] = M68K_BRA_S_0;
  208. Optimized = TRUE;
  209. }
  210. break;
  211. // Optimize 2-byte relative relocs.
  212. case 2:
  213. OpcodeLocation = RelocLocation - 2;
  214. Opcode = Data + OpcodeLocation;
  215. // Check if the reloc belongs to a BSR.W, and that there
  216. // is nothing in our way.
  217. if ((Opcode [0] == M68K_BSR_W_0) && (Opcode [1] == M68K_BSR_W_1) && (IsBinaryDataRange (Section, OpcodeLocation, RTSEnd, Reloc)))
  218. {
  219. // Optimize it into a JMP.
  220. Opcode [0] = M68K_BRA_W_0;
  221. Opcode [1] = M68K_BRA_W_1;
  222. Optimized = TRUE;
  223. }
  224. break;
  225. }
  226. }
  227. else
  228. {
  229. // Optimize 4-byte absolute relocs.
  230. if (Reloc->Size == 4)
  231. {
  232. OpcodeLocation = RelocLocation - 2;
  233. Opcode = Data + OpcodeLocation;
  234. // Check if the reloc belongs to a JSR, and that there is
  235. // nothing in our way.
  236. if ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1) && (IsBinaryDataRange (Section, OpcodeLocation, RTSEnd, Reloc)))
  237. {
  238. // Optimize it into a JMP.
  239. Opcode [0] = M68K_JMP_0;
  240. Opcode [1] = M68K_JMP_1;
  241. Optimized = TRUE;
  242. }
  243. }
  244. }
  245. // Remove the RTS.
  246. if (Optimized)
  247. TargetDistance -= M68kCutOrFillRange (Section, RelocEnd, RTSEnd, OptimizeInfo);
  248. }
  249. }
  250. // Only branch fixes and optimizations make sense for relative relocs.
  251. if (Reloc->Relative)
  252. {
  253. // Check if it is a 1-byte relative reloc at the end of the
  254. // section, pointing to the next instruction. This means that
  255. // the value will probably be 0, which is invalid for 1-byte
  256. // branches.
  257. if ((Reloc->Size == 1) && (TargetDistance == 0))
  258. {
  259. OpcodeLocation = RelocLocation - 1;
  260. Opcode = Data + OpcodeLocation;
  261. // Check whether it belongs to a branch. If it does, it
  262. // is invalid.
  263. if (((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_S_0) && (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 2, Reloc)))
  264. {
  265. // If it is a BSR.S, removing it would modify the
  266. // semantics. Instead, insert a NOP at the end of the
  267. // section (if this is really the end of the section).
  268. if (Opcode [0] == M68K_BSR_S_0)
  269. {
  270. if (OpcodeLocation + 2 == Section->Size)
  271. {
  272. // Allocate two bytes at the end of the section.
  273. I1 *Space = AllocateSpaceInSection (Section, 2);
  274. if (Space)
  275. {
  276. Space [0] = M68K_NOP_0;
  277. Space [1] = M68K_NOP_1;
  278. }
  279. }
  280. }
  281. else
  282. {
  283. // Delete the reloc.
  284. FreeReloc (Reloc);
  285. // Cut or fill the gained space.
  286. M68kCutOrFillRange (Section, OpcodeLocation, OpcodeLocation + 2, OptimizeInfo);
  287. // Since the reloc has been removed, return from the function.
  288. return;
  289. }
  290. }
  291. }
  292. else if (OptimizeInfo->OptimizeBranches && (Reloc->Size == 2))
  293. {
  294. OpcodeLocation = RelocLocation - 2;
  295. Opcode = Data + OpcodeLocation;
  296. // Check whether the reloc belongs to a branch.
  297. if (((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_W_0) && (Opcode [1] == M68K_Bcc_W_1) && (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 4, Reloc)))
  298. {
  299. // Check whether it can be removed.
  300. if ((TargetDistance == 2) && (Opcode [0] != M68K_BSR_W_0))
  301. {
  302. // Delete the reloc.
  303. FreeReloc (Reloc);
  304. // Cut or fill the gained space.
  305. M68kCutOrFillRange (Section, OpcodeLocation, OpcodeLocation + 4, OptimizeInfo);
  306. // Since the reloc has been removed, return from the function.
  307. return;
  308. }
  309. // Check whether it is near enough for a Bcc.S.
  310. else if ((TargetDistance != 2) && (M68K_REL_OK (TargetDistance, 1)))
  311. {
  312. // Optimize it into a Bcc.S.
  313. Opcode [0] = M68K_Bcc_S_0 | (Data [OpcodeLocation] & (~M68K_Bcc_MASK_0));
  314. Opcode [1] = 0;
  315. // Change the reloc to 1-byte relative.
  316. Reloc->Size = 1;
  317. // Adjust the location.
  318. Reloc->Location--;
  319. RelocLocation--;
  320. // Adjust the offset. A short branch always
  321. // uses the next instruction as a reference.
  322. Reloc->FixedOffset--;
  323. // Cut or fill the gained space.
  324. M68kCutOrFillRange (Section, OpcodeLocation + 2, OpcodeLocation + 4, OptimizeInfo);
  325. }
  326. }
  327. }
  328. }
  329. // Other than that, only change 4-byte absolute relocs.
  330. else if (Reloc->Size == 4)
  331. {
  332. // Most opcodes are two bytes long, and the reloc follows
  333. // immediately.
  334. OpcodeLocation = RelocLocation - 2;
  335. // Safety check before accessing the section data.
  336. if (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 6, Reloc))
  337. {
  338. Opcode = Data + OpcodeLocation;
  339. {
  340. // *** Branch Optimization ***
  341. // Try to optimize a 4-byte absolute branch into a 2-byte or 1-byte
  342. // relative one.
  343. // Check whether the reloc belongs to a branch.
  344. BOOLEAN IsJMP = ((Opcode [0] == M68K_JMP_0) && (Opcode [1] == M68K_JMP_1));
  345. BOOLEAN IsJSR = ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1));
  346. if ((IsJMP || IsJSR))
  347. {
  348. // Check whether it can be removed.
  349. if (OptimizeInfo->OptimizeBranches && (TargetDistance == 4) && IsJMP)
  350. {
  351. // Delete the reloc.
  352. FreeReloc (Reloc);
  353. // Cut or fill the gained space.
  354. M68kCutOrFillRange (Section, OpcodeLocation, OpcodeLocation + 6, OptimizeInfo);
  355. OptimizeInfo->OptimizeBranchesResult++;
  356. }
  357. // Check whether it is near enough for a BRA.S or BSR.S.
  358. else if (OptimizeInfo->OptimizeBranches && (TargetDistance != 4) && (M68K_REL_OK (TargetDistance, 1)))
  359. {
  360. // Optimize it into a BRA.S or BSR.S.
  361. Opcode [0] = (IsJSR ? M68K_BSR_S_0 : M68K_BRA_S_0);
  362. Opcode [1] = 0;
  363. // Change the reloc to 1-byte relative.
  364. Reloc->Relative = TRUE;
  365. Reloc->Size = 1;
  366. // Adjust the location.
  367. Reloc->Location--;
  368. // Adjust the offset. A short branch always
  369. // uses the next instruction as a reference.
  370. Reloc->FixedOffset--;
  371. // Cut or fill the gained space.
  372. M68kCutOrFillRange (Section, OpcodeLocation + 2, OpcodeLocation + 6, OptimizeInfo);
  373. OptimizeInfo->OptimizeBranchesResult++;
  374. }
  375. // Treat it as a normal absolute to relative optimization.
  376. else
  377. {
  378. BOOLEAN BranchOptimized = FALSE;
  379. // Check if the target is near enough for a BRA/BSR.
  380. if (M68K_REL_OK (TargetDistance, 2))
  381. {
  382. OptimizeInfo->OptimizeBranchesResult++;
  383. if (OptimizeInfo->NearAssemblyResult >= 0)
  384. OptimizeInfo->NearAssemblyResult += 2;
  385. if (OptimizeInfo->OptimizeBranches)
  386. {
  387. // Optimize it into a BRA.W or BSR.W.
  388. Opcode [0] = (IsJSR ? M68K_BSR_W_0 : M68K_BRA_W_0);
  389. Opcode [1] = (IsJSR ? M68K_BSR_W_1 : M68K_BRA_W_1);
  390. // Change the reloc to 2-byte relative.
  391. Reloc->Relative = TRUE;
  392. Reloc->Size = 2;
  393. // Cut or fill the gained space.
  394. M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
  395. // Do not try to do anything else with this branch.
  396. BranchOptimized = TRUE;
  397. }
  398. }
  399. else
  400. {
  401. // The target is not near enough. This means that near
  402. // assembly is not possible.
  403. OptimizeInfo->NearAssemblyResult = -1;
  404. }
  405. if (!BranchOptimized)
  406. {
  407. // Optimize F-Line jumps if desired.
  408. OptimizeInfo->UseFLineJumpsResult++;
  409. if (OptimizeInfo->Use4ByteFLineJumps)
  410. M68kEmuMakeFLineJump (Reloc, Opcode, IsJSR);
  411. else if (OptimizeInfo->UseFLineJumps)
  412. M68kTIOSMakeFLineJump (Reloc, Opcode, IsJSR);
  413. else
  414. return;
  415. // Cut or fill the gained space.
  416. M68kCutOrFillRange (Section, Reloc->Location + Reloc->Size, OpcodeLocation + 6, OptimizeInfo);
  417. }
  418. }
  419. }
  420. // Not a branch.
  421. else
  422. {
  423. BOOLEAN Optimized = FALSE;
  424. // Check if the target is near enough.
  425. if (M68K_REL_OK (TargetDistance, 2))
  426. {
  427. // *** Move Optimization ***
  428. // Optimize LEA(.L) var.L,reg into
  429. // LEA(.L) var.W(%PC),reg.
  430. if ((((Opcode [0] & M68K_LEA_ABS_MASK_0) == M68K_LEA_ABS_0) && ((Opcode [1] & M68K_LEA_ABS_MASK_1) == M68K_LEA_ABS_1))
  431. // Optimize PEA(.L) var.L into PEA(.L) var.W(%PC).
  432. || ((Opcode [0] == M68K_PEA_ABS_0) && (Opcode [1] == M68K_PEA_ABS_1))
  433. // Optimize MOVE.x var.L,reg/(reg)/(reg)+ into
  434. // MOVE.x var.W(%PC),reg/(reg)/(reg)+.
  435. || (((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)
  436. && (!((Opcode [0] & M68K_MOVE_ABS_REG_INV_0_MASK_0) == M68K_MOVE_ABS_REG_INV_0_0))
  437. && (!(((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))))
  438. // Optimize MOVE.x var.L,-(reg) into
  439. // MOVE.x var.W(%PC),-(reg).
  440. || (((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)
  441. && (!((Opcode [0] & M68K_MOVE_ABS_PREDEC_INV_0_MASK_0) == M68K_MOVE_ABS_PREDEC_INV_0_0))))
  442. {
  443. OptimizeInfo->OptimizeMovesResult++;
  444. if (OptimizeInfo->NearAssemblyResult >= 0)
  445. OptimizeInfo->NearAssemblyResult += 2;
  446. if (OptimizeInfo->OptimizeMoves)
  447. {
  448. // Turn the opcode into a pc-relative one.
  449. M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
  450. // Do everything else later.
  451. Optimized = TRUE;
  452. }
  453. }
  454. // *** Test Optimization ***
  455. // Optimize CMP.x var.L,reg into CMP.x var.W(%PC),reg.
  456. 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)
  457. && (!((Opcode [1] & M68K_CMP_ABS_REG_INV_0_MASK_1) == M68K_CMP_ABS_REG_INV_0_1)))
  458. // Optimize BTST reg,var.L into BTST reg,var.W(%PC).
  459. || (((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)))
  460. {
  461. OptimizeInfo->OptimizeTestsResult++;
  462. if (OptimizeInfo->NearAssemblyResult >= 0)
  463. OptimizeInfo->NearAssemblyResult += 2;
  464. if (OptimizeInfo->OptimizeTests)
  465. {
  466. // Turn the opcode into a pc-relative one.
  467. M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
  468. // Do everything else later.
  469. Optimized = TRUE;
  470. }
  471. }
  472. // *** Calculation Optimization ***
  473. // Optimize ADD/SUB.x var.L,reg into
  474. // ADD/SUB.x var.W(%PC),reg.
  475. 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))
  476. || (((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))
  477. // Optimize MUL/DIV.x var.L,reg into
  478. // MUL/DIV.x var.W(%PC),reg.
  479. || (((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))
  480. // Optimize AND/OR.x var.L,reg into
  481. // AND/OR.x var.W(%PC),reg.
  482. || (((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)))
  483. {
  484. OptimizeInfo->OptimizeCalcsResult++;
  485. if (OptimizeInfo->NearAssemblyResult >= 0)
  486. OptimizeInfo->NearAssemblyResult += 2;
  487. if (OptimizeInfo->OptimizeCalcs)
  488. {
  489. // Turn the opcode into a pc-relative one.
  490. M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
  491. // Do everything else later.
  492. Optimized = TRUE;
  493. }
  494. }
  495. }
  496. if (Optimized)
  497. {
  498. // Change the reloc to 2-byte relative.
  499. Reloc->Relative = TRUE;
  500. Reloc->Size = 2;
  501. // Cut or fill the gained space.
  502. M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
  503. }
  504. else
  505. {
  506. // Check if the target is near enough.
  507. if (M68K_REL_OK (TargetDistance, 2))
  508. {
  509. if (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
  510. {
  511. // Optimize MOVE.x var.L,ofs(reg) into
  512. // MOVE.x var.W(%PC),ofs(reg)
  513. // We cannot handle this above because of the
  514. // offset, which comes after the reloc.
  515. 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)
  516. && (!((Opcode [0] & M68K_MOVE_ABS_OFSREG_INV_0_MASK_0) == M68K_MOVE_ABS_OFSREG_INV_0_0)))
  517. {
  518. OptimizeInfo->OptimizeMovesResult++;
  519. if (OptimizeInfo->NearAssemblyResult >= 0)
  520. OptimizeInfo->NearAssemblyResult += 2;
  521. if (OptimizeInfo->OptimizeMoves)
  522. {
  523. // Turn the opcode into a pc-relative one.
  524. M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
  525. // Move the offset to the correct place.
  526. Opcode [4] = Opcode [6];
  527. Opcode [5] = Opcode [7];
  528. // Change the reloc to 2-byte relative.
  529. Reloc->Relative = TRUE;
  530. Reloc->Size = 2;
  531. Optimized = TRUE;
  532. // Cut or fill the gained space.
  533. M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
  534. }
  535. }
  536. }
  537. {
  538. OpcodeLocation = RelocLocation - 4;
  539. Opcode = Data + OpcodeLocation;
  540. if (!Optimized && IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
  541. {
  542. // Optimize MOVEM.x var.L,regs into
  543. // MOVEM var.W(%PC),regs.
  544. 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))
  545. {
  546. OptimizeInfo->OptimizeMovesResult++;
  547. if (OptimizeInfo->NearAssemblyResult >= 0)
  548. OptimizeInfo->NearAssemblyResult += 2;
  549. if (OptimizeInfo->OptimizeMoves)
  550. {
  551. // Turn the opcode into a pc-relative one.
  552. M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
  553. // Change the reloc to 2-byte relative.
  554. Reloc->Relative = TRUE;
  555. Reloc->Size = 2;
  556. // Cut or fill the gained space.
  557. M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
  558. }
  559. }
  560. // Optimize BTST #num,var.L into
  561. // BTST #num,var.W(%PC).
  562. else if ((Opcode [0] == M68K_BTST_IMM_ABS_0) && (Opcode [1] == M68K_BTST_IMM_ABS_1) && (Opcode [2] == M68K_BTST_IMM_ABS_2))
  563. {
  564. OptimizeInfo->OptimizeTestsResult++;
  565. if (OptimizeInfo->NearAssemblyResult >= 0)
  566. OptimizeInfo->NearAssemblyResult += 2;
  567. if (OptimizeInfo->OptimizeTests)
  568. {
  569. // Turn the opcode into a pc-relative one.
  570. M68K_MAKE_REL_OPCODE_1 (Opcode [1]);
  571. // Change the reloc to 2-byte relative.
  572. Reloc->Relative = TRUE;
  573. Reloc->Size = 2;
  574. // Cut or fill the gained space.
  575. M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
  576. }
  577. }
  578. }
  579. }
  580. }
  581. else
  582. {
  583. // The target is not near enough. This means that near
  584. // assembly is not possible.
  585. OptimizeInfo->NearAssemblyResult = -1;
  586. }
  587. }
  588. }
  589. }
  590. }
  591. }
  592. }
  593. #ifdef FLASH_OS_SUPPORT
  594. static void M68kFixBssAbs16 (RELOC *Reloc, OPTIMIZE_INFO *OptimizeInfo)
  595. {
  596. SECTION *Section = Reloc->Parent;
  597. I1 *Data = Section->Data;
  598. OFFSET RelocLocation = Reloc->Location;
  599. OFFSET OpcodeLocation;
  600. I1 *Opcode;
  601. // Return if there is no data, the reloc is not optimizable or if the reloc size is not 4 bytes.
  602. // If the section doesn't support the cut ranges, it doesn't worth the effort (we don't any reloc to emit).
  603. if (!Data || Reloc->Unoptimizable || Reloc->Size != 4 || !Section->CanCutRanges)
  604. return;
  605. if (!(Reloc->Target.Symbol))
  606. return;
  607. // Test is the reloc is optimizable: the absolute address muse be < 2^15
  608. OpcodeLocation = GetLocationOffset (Reloc->Target.Symbol->Parent, &(Reloc->Target)) + Reloc->FixedOffset;
  609. OpcodeLocation += (OFFSET) (OptimizeInfo->FlashOSBSSStart);
  610. if (OpcodeLocation >= 0x7FFF)
  611. return;
  612. // Most opcodes are two bytes long, and the reloc follows immediately.
  613. OpcodeLocation = RelocLocation - 2;
  614. // Safety check before accessing the section data.
  615. if (!IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 6, Reloc))
  616. return;
  617. Opcode = Data + OpcodeLocation;
  618. // *** Move Optimization ***
  619. // Optimize LEA(.L) var.L,reg into LEA(.w) var.W),reg.
  620. if ((((Opcode [0] & M68K_LEA_ABS_MASK_0) == M68K_LEA_ABS_0) && ((Opcode [1] & M68K_LEA_ABS_MASK_1) == M68K_LEA_ABS_1))
  621. // Optimize PEA(.L) var.L into PEA(.L) var.W(%PC).
  622. || ((Opcode [0] == M68K_PEA_ABS_0) && (Opcode [1] == M68K_PEA_ABS_1))
  623. // Optimize MOVE.x var.L,reg/(reg)/(reg)+ into
  624. // MOVE.x var.W(%PC),reg/(reg)/(reg)+.
  625. || (((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)
  626. && (!((Opcode [0] & M68K_MOVE_ABS_REG_INV_0_MASK_0) == M68K_MOVE_ABS_REG_INV_0_0))
  627. && (!(((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))))
  628. // Optimize MOVE.x var.L,-(reg) into
  629. // MOVE.x var.W(%PC),-(reg).
  630. || (((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)
  631. && (!((Opcode [0] & M68K_MOVE_ABS_PREDEC_INV_0_MASK_0) == M68K_MOVE_ABS_PREDEC_INV_0_0))))
  632. {
  633. OptimizeInfo->OptimizeMovesResult++;
  634. if (OptimizeInfo->OptimizeMoves)
  635. {
  636. // Turn the opcode into an abs16 one.
  637. M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
  638. // Change the reloc to 2-byte absolute.
  639. Reloc->Size = 2;
  640. // Cut or fill the gained space.
  641. M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
  642. }
  643. return;
  644. }
  645. // *** Test Optimization ***
  646. // Optimize CMP.x var.L,reg into CMP.x var.W(%PC),reg.
  647. 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)
  648. && (!((Opcode [1] & M68K_CMP_ABS_REG_INV_0_MASK_1) == M68K_CMP_ABS_REG_INV_0_1)))
  649. // Optimize BTST reg,var.L into BTST reg,var.W(%PC).
  650. || (((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)))
  651. {
  652. OptimizeInfo->OptimizeTestsResult++;
  653. if (OptimizeInfo->OptimizeTests)
  654. {
  655. // Turn the opcode into a abs16 one.
  656. M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
  657. // Change the reloc to 2-byte absolute.
  658. Reloc->Size = 2;
  659. // Cut or fill the gained space.
  660. M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
  661. }
  662. return;
  663. }
  664. // *** Calculation Optimization ***
  665. // Optimize ADD/SUB.x var.L,reg into
  666. // ADD/SUB.x var.W(%PC),reg.
  667. 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))
  668. || (((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))
  669. // Optimize MUL/DIV.x var.L,reg into
  670. // MUL/DIV.x var.W(%PC),reg.
  671. || (((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))
  672. // Optimize AND/OR.x var.L,reg into
  673. // AND/OR.x var.W(%PC),reg.
  674. || (((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)))
  675. {
  676. OptimizeInfo->OptimizeCalcsResult++;
  677. if (OptimizeInfo->OptimizeCalcs)
  678. {
  679. // Turn the opcode into a abs16 one.
  680. M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
  681. // Change the reloc to 2-byte .
  682. Reloc->Size = 2;
  683. // Cut or fill the gained space.
  684. M68kCutOrFillRange (Section, OpcodeLocation + 4, OpcodeLocation + 6, OptimizeInfo);
  685. }
  686. return;
  687. }
  688. // Check opcodes of 8 bytes without prefix
  689. if (!IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
  690. return;
  691. // Optimize MOVE.x var.L,ofs(reg) into
  692. // MOVE.x var.W,ofs(reg)
  693. // We cannot handle this above because of the
  694. // offset, which comes after the reloc.
  695. 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)
  696. && (!((Opcode [0] & M68K_MOVE_ABS_OFSREG_INV_0_MASK_0) == M68K_MOVE_ABS_OFSREG_INV_0_0)))
  697. {
  698. OptimizeInfo->OptimizeMovesResult++;
  699. if (OptimizeInfo->OptimizeMoves)
  700. {
  701. // Turn the opcode into a abs16 one.
  702. M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
  703. // Move the offset to the correct place.
  704. Opcode [4] = Opcode [6];
  705. Opcode [5] = Opcode [7];
  706. // Change the reloc to 2-byte abs16.
  707. Reloc->Size = 2;
  708. // Cut or fill the gained space.
  709. M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
  710. }
  711. return;
  712. }
  713. // Now Opcode are bigger (8 bytes)
  714. OpcodeLocation = RelocLocation - 4;
  715. Opcode = Data + OpcodeLocation;
  716. if (!IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 8, Reloc))
  717. return;
  718. // Optimize MOVEM.x var.L,regs into
  719. // MOVEM var.W,regs.
  720. 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))
  721. {
  722. OptimizeInfo->OptimizeMovesResult++;
  723. if (OptimizeInfo->OptimizeMoves)
  724. {
  725. // Turn the opcode into a abs16 one.
  726. M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
  727. // Change the reloc to 2-byte relative.
  728. Reloc->Size = 2;
  729. // Cut or fill the gained space.
  730. M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
  731. }
  732. }
  733. // Optimize BTST #num,var.L into
  734. // BTST #num,var.W
  735. if ((Opcode [0] == M68K_BTST_IMM_ABS_0) && (Opcode [1] == M68K_BTST_IMM_ABS_1) && (Opcode [2] == M68K_BTST_IMM_ABS_2))
  736. {
  737. OptimizeInfo->OptimizeTestsResult++;
  738. if (OptimizeInfo->OptimizeTests)
  739. {
  740. // Turn the opcode into a abs16 one.
  741. M68K_MAKE_ABS16_OPCODE_1 (Opcode [1]);
  742. // Change the reloc to 2-byte absolute.
  743. Reloc->Size = 2;
  744. // Cut or fill the gained space.
  745. M68kCutOrFillRange (Section, OpcodeLocation + 6, OpcodeLocation + 8, OptimizeInfo);
  746. }
  747. }
  748. // Nothing can be done
  749. return;
  750. }
  751. #endif
  752. // Checks if a specific reloc might be optimizable. This is currently
  753. // limited to 4-bytes absolute relocs because that is the only case
  754. // this is needed for.
  755. BOOLEAN M68kIsRelocOptimizable (const RELOC *Reloc)
  756. {
  757. if (Reloc->Unoptimizable) return FALSE;
  758. if (Reloc->Size == 4 && (!(Reloc->Relative)))
  759. {
  760. const SECTION *Section = Reloc->Parent;
  761. // Most opcodes are two bytes long, and the reloc follows
  762. // immediately.
  763. OFFSET OpcodeLocation = Reloc->Location - 2;
  764. // Safety check before accessing the section data.
  765. if (IsBinaryDataRange (Section, OpcodeLocation, OpcodeLocation + 6, Reloc))
  766. {
  767. const I1 *Opcode = Section->Data + OpcodeLocation;
  768. // *** Branch Optimization ***
  769. if (((Opcode [0] == M68K_JMP_0) && (Opcode [1] == M68K_JMP_1))
  770. || ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1))
  771. // *** Move Optimization ***
  772. || (((Opcode [0] & M68K_LEA_ABS_MASK_0) == M68K_LEA_ABS_0) && ((Opcode [1] & M68K_LEA_ABS_MASK_1) == M68K_LEA_ABS_1))
  773. || ((Opcode [0] == M68K_PEA_ABS_0) && (Opcode [1] == M68K_PEA_ABS_1))
  774. || (((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)
  775. && (!((Opcode [0] & M68K_MOVE_ABS_REG_INV_0_MASK_0) == M68K_MOVE_ABS_REG_INV_0_0))
  776. && (!(((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))))
  777. || (((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)
  778. && (!((Opcode [0] & M68K_MOVE_ABS_PREDEC_INV_0_MASK_0) == M68K_MOVE_ABS_PREDEC_INV_0_0)))
  779. || (((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)
  780. && (!((Opcode [0] & M68K_MOVE_ABS_OFSREG_INV_0_MASK_0) == M68K_MOVE_ABS_OFSREG_INV_0_0)))
  781. || (((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))
  782. // *** Test Optimization ***
  783. || (((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)
  784. && (!((Opcode [1] & M68K_CMP_ABS_REG_INV_0_MASK_1) == M68K_CMP_ABS_REG_INV_0_1)))
  785. || (((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))
  786. || ((Opcode [0] == M68K_BTST_IMM_ABS_0) && (Opcode [1] == M68K_BTST_IMM_ABS_1) && (Opcode [2] == M68K_BTST_IMM_ABS_2))
  787. // *** Calculation Optimization ***
  788. || (((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))
  789. || (((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))
  790. || (((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))
  791. || (((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)))
  792. return TRUE;
  793. }
  794. }
  795. return FALSE;
  796. }
  797. // If the section ends with exactly one NOP instruction, remove the NOP.
  798. void M68kRemoveTrailingNOP (SECTION *Section)
  799. {
  800. I1 *Data = Section->Data;
  801. SIZE Size = Section->Size;
  802. // Validate basic circumstances.
  803. if (Data && (Size >= 4)
  804. // Check for NOP in last instruction.
  805. && (Data [Size - 2] == M68K_NOP_0) && (Data [Size - 1] == M68K_NOP_1) && (IsBinaryDataRange (Section, Size - 2, Size, NULL))
  806. // Check for NOP in previous instruction (which would mean that we
  807. // actually want the NOPs to be there).
  808. && (!((Data [Size - 4] == M68K_NOP_0) && (Data [Size - 3] == M68K_NOP_1)))
  809. // Check if something prevents us from shrinking the section.
  810. && (CanShrinkSection (Section, Size - 2, NULL)))
  811. // Cut the NOP away.
  812. CutSection (Section, Size - 2);
  813. }
  814. // Fix and return the target offset of a reloc.
  815. // In particular, for 1-byte relative relocs, the target offset is
  816. // increased by 1, so the the reloc points to the symbol and not to
  817. // the symbol minus 1.
  818. OFFSET M68kFixTargetOffset (OFFSET Offset, SIZE RelocSize, BOOLEAN RelocRelative)
  819. {
  820. if (RelocRelative && (RelocSize == 1))
  821. return Offset + 1;
  822. else
  823. return Offset;
  824. }
  825. #define SHORT_IMPORTANCE 2048
  826. // Called by M68kGetSectionRelationship; see below.
  827. static COUNT M68kGetRelocImportance (const RELOC *Reloc, OFFSET Offset)
  828. {
  829. SECTION *Section = Reloc->Parent;
  830. if (Reloc->Unoptimizable) return 0;
  831. // Byte offsets are useful only for jumps or branches, so detect
  832. // them.
  833. if (M68K_REL_OK (Offset, 1))
  834. {
  835. OFFSET RelocLocation = Reloc->Location;
  836. OFFSET OpcodeLocation = RelocLocation - 2;
  837. I1 *Opcode = Section->Data + OpcodeLocation;
  838. if (Reloc->Size == 4)
  839. {
  840. // Check whether the reloc belongs to a branch.
  841. BOOLEAN IsJMP = ((Opcode [0] == M68K_JMP_0)
  842. && (Opcode [1] == M68K_JMP_1));
  843. BOOLEAN IsJSR = ((Opcode [0] == M68K_JSR_0)
  844. && (Opcode [1] == M68K_JSR_1));
  845. if ((IsJMP || IsJSR)
  846. && IsBinaryDataRange (Section,
  847. OpcodeLocation,
  848. OpcodeLocation + 6, Reloc))
  849. {
  850. return ((Offset == 4 && IsJMP) ? SHORT_IMPORTANCE * 2
  851. : SHORT_IMPORTANCE);
  852. }
  853. }
  854. else if (Reloc->Size == 2)
  855. {
  856. // Check whether the reloc belongs to a branch.
  857. if ((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_W_0
  858. && Opcode [1] == M68K_Bcc_W_1
  859. && IsBinaryDataRange (Section,
  860. OpcodeLocation,
  861. OpcodeLocation + 4, Reloc))
  862. {
  863. return (Offset == 2 && !(Opcode [0] == M68K_BSR_W_0
  864. && Opcode [1] == M68K_BSR_W_1)) ? SHORT_IMPORTANCE * 2
  865. : SHORT_IMPORTANCE;
  866. }
  867. }
  868. }
  869. // Everything else is not optimizable.
  870. return 0;
  871. }
  872. // Determines the amount of relationship between the two sections, for the
  873. // situation that Section2 might be put just behind Section1. A reference
  874. // that could potentially be short gets 2048 points; a reference that could
  875. // potentially be removed gets twice as much.
  876. // The effect is that a section with one potentially short reference can
  877. // be at most 2048 bytes long for being inserted immediately by reordering,
  878. // and so on.
  879. COUNT M68kGetSectionRelationship (const SECTION *Section1, const SECTION *Section2)
  880. {
  881. COUNT Result = 0;
  882. const RELOC *Reloc;
  883. for_each (Reloc, Section1->Relocs)
  884. {
  885. const SYMBOL *TargetSymbol = Reloc->Target.Symbol;
  886. if (TargetSymbol && TargetSymbol->Parent == Section2)
  887. Result += M68kGetRelocImportance (Reloc, Section1->Size - Reloc->Location + TargetSymbol->Location + Reloc->Target.Offset + Reloc->FixedOffset);
  888. }
  889. for_each (Reloc, Section2->Relocs)
  890. {
  891. const SYMBOL *TargetSymbol = Reloc->Target.Symbol;
  892. if (TargetSymbol && TargetSymbol->Parent == Section1)
  893. Result += M68kGetRelocImportance (Reloc, TargetSymbol->Location + Reloc->Target.Offset + Reloc->FixedOffset - Section1->Size - Reloc->Location);
  894. }
  895. return Result;
  896. }
  897. // Compute an estimate of how important it is to put the section containing this
  898. // reloc next during local section reordering.
  899. // Here are the estimates used:
  900. // 0-byte branches save 6 bytes and 1 reloc and cannot be deferred -> 512 points
  901. // 2-byte branches save 4 bytes and 1 reloc and can rarely be deferred -> 256
  902. // PC-relative references save 2 bytes and 1 reloc. They can be deferred based
  903. // on how far the accumulated distance is. We compute between 0 and 32 points
  904. // based on the offset, with the formula: (offset^2>>25)+2.
  905. COUNT M68kComputeRelocGoodness(OFFSET Offset, RELOC *Reloc)
  906. {
  907. SECTION *Section = Reloc->Parent;
  908. if (Reloc->Unoptimizable) return 0;
  909. // Byte offsets are useful only for jumps or branches, so detect
  910. // them.
  911. if (M68K_REL_OK (Offset, 1))
  912. {
  913. OFFSET RelocLocation = Reloc->Location;
  914. OFFSET OpcodeLocation = RelocLocation - 2;
  915. I1 *Opcode = Section->Data + OpcodeLocation;
  916. if (Reloc->Size == 4)
  917. {
  918. // Check whether the reloc belongs to a branch.
  919. BOOLEAN IsJMP = ((Opcode [0] == M68K_JMP_0)
  920. && (Opcode [1] == M68K_JMP_1));
  921. BOOLEAN IsJSR = ((Opcode [0] == M68K_JSR_0)
  922. && (Opcode [1] == M68K_JSR_1));
  923. if ((IsJMP || IsJSR)
  924. && IsBinaryDataRange (Section,
  925. OpcodeLocation,
  926. OpcodeLocation + 6, Reloc))
  927. {
  928. return (Offset == 4 && IsJMP) ? 512 : 256;
  929. }
  930. }
  931. else if (Reloc->Size == 2)
  932. {
  933. // Check whether the reloc belongs to a branch.
  934. if ((Opcode [0] & M68K_Bcc_MASK_0) == M68K_Bcc_W_0
  935. && Opcode [1] == M68K_Bcc_W_1
  936. && IsBinaryDataRange (Section,
  937. OpcodeLocation,
  938. OpcodeLocation + 4, Reloc))
  939. {
  940. return (Offset == 2 && !(Opcode [0] == M68K_BSR_W_0
  941. && Opcode [1] == M68K_BSR_W_1)) ? 512
  942. : 256;
  943. }
  944. }
  945. }
  946. // Word offsets are useful everywhere where a PC-relative reference is
  947. // possible. So look for those places.
  948. if (M68K_REL_OK (Offset, 2))
  949. {
  950. OFFSET RelocLocation = Reloc->Location;
  951. OFFSET OpcodeLocation = RelocLocation - 2;
  952. I1 *Opcode = Section->Data + OpcodeLocation;
  953. // Safety check before accessing the section data.
  954. if (Reloc->Size == 4 && IsBinaryDataRange (Section, OpcodeLocation,
  955. OpcodeLocation + 6, Reloc))
  956. {
  957. // Check whether the reloc belongs to a branch.
  958. if (((Opcode [0] == M68K_JMP_0) && (Opcode [1] == M68K_JMP_1))
  959. || ((Opcode [0] == M68K_JSR_0) && (Opcode [1] == M68K_JSR_1))
  960. // Optimize LEA(.L) var.L,reg into
  961. // LEA(.L) var.W(%PC),reg.
  962. || (((Opcode [0] & M68K_LEA_ABS_MASK_0) == M68K_LEA_ABS_0) && ((Opcode [1] & M68K_LEA_ABS_MASK_1) == M68K_LEA_ABS_1))
  963. // Optimize PEA(.L) var.L into PEA(.L) var.W(%PC).
  964. || ((Opcode [0] == M68K_PEA_ABS_0) && (Opcode [1] == M68K_PEA_ABS_1))
  965. // Optimize MOVE.x var.L,reg/(reg)/(reg)+ into
  966. // MOVE.x var.W(%PC),reg/(reg)/(reg)+.
  967. || (((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)
  968. && (!((Opcode [0] & M68K_MOVE_ABS_REG_INV_0_MASK_0) == M68K_MOVE_ABS_REG_INV_0_0))
  969. && (!(((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))))
  970. // Optimize MOVE.x var.L,-(reg) into
  971. // MOVE.x var.W(%PC),-(reg).
  972. || (((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)
  973. && (!((Opcode [0] & M68K_MOVE_ABS_PREDEC_INV_0_MASK_0) == M68K_MOVE_ABS_PREDEC_INV_0_0)))
  974. // Optimize CMP.x var.L,reg into CMP.x var.W(%PC),reg.
  975. || (((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)
  976. && (!((Opcode [1] & M68K_CMP_ABS_REG_INV_0_MASK_1) == M68K_CMP_ABS_REG_INV_0_1)))
  977. // Optimize BTST reg,var.L into BTST reg,var.W(%PC).
  978. || (((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))
  979. // Optimize ADD/SUB.x var.L,reg into
  980. // ADD/SUB.x var.W(%PC),reg.
  981. || (((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))
  982. || (((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))
  983. // Optimize MUL/DIV.x var.L,reg into
  984. // MUL/DIV.x var.W(%PC),reg.
  985. || (((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))
  986. // Optimize AND/OR.x var.L,reg into
  987. // AND/OR.x var.W(%PC),reg.
  988. || (((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)))
  989. {
  990. return ((Offset * Offset) >> 25);
  991. }
  992. }
  993. }
  994. // Everything else is not optimizable, so ignore it for section reordering.
  995. return 0;
  996. }