cutrange.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /* fix_cutr.c: Routines for range cutting
  2. Copyright (C) 2003-2005 Kevin Kofler
  3. Portions taken from manip.c, Copyright (C) 2002-2003 Sebastian Reichelt
  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 "cutrange.h"
  16. #include "../manip.h"
  17. #include <stdlib.h>
  18. #include <string.h>
  19. // Check whether the segments which overlap with the interval [Start,End)
  20. // allow range-cutting.
  21. BOOLEAN CanCutRange (SECTION *Section, OFFSET Start, OFFSET End)
  22. {
  23. // If the section is as a whole does not allow range-cutting,
  24. // the individual segments implicitly do not allow this either.
  25. if (!(Section->CanCutRanges))
  26. return FALSE;
  27. else
  28. {
  29. SEGMENT *Segment;
  30. for (Segment = FindSegment (Section, Start, End); Segment && (Segment->Location.Start->Location < End); Segment = GetNext (Segment))
  31. {
  32. if (!(Segment->CanCutRanges))
  33. return FALSE;
  34. }
  35. return TRUE;
  36. }
  37. }
  38. // Adjust a referenced location to reflect the removal of the
  39. // specified range. The location needs to be adjusted if the range
  40. // is between the location's symbol and the place it actually points
  41. // to.
  42. static void AdjustLocationForRangeCut (RELOC *Reloc, LOCATION *Location, OFFSET Start, OFFSET End)
  43. {
  44. // Length of the range that has been cut.
  45. OFFSET RangeLength = End - Start;
  46. // Get the location of the target symbol and of the actual target.
  47. OFFSET SymbolLocation = Location->Symbol->Location;
  48. OFFSET TargetLocation = SymbolLocation + Location->Offset;
  49. // Make sure the symbol is not in the range we will cut.
  50. if (!((SymbolLocation > Start) && (SymbolLocation < End)))
  51. {
  52. // Make sure the target is not in the range we will cut.
  53. if ((TargetLocation > Start) && (TargetLocation < End))
  54. {
  55. Warning (GetFileName (Reloc->Parent, Reloc->Location), "Reloc at 0x%lX in section `%s' pointing to %s%+ld in a range which is being optimized away.",
  56. (unsigned long) Reloc->Location, Reloc->Parent->SectionSymbol->Name, Location->Symbol->Name, (long) Location->Offset);
  57. // Set location value to Start.
  58. Location->Offset = Start - SymbolLocation;
  59. }
  60. else
  61. {
  62. // We will adjust the symbol address in the next step, if
  63. // the range that has been cut is between SymbolLocation and
  64. // TargetLocation. Two cases need adjustment now:
  65. // 1. The target is >= End, but the actual symbol is <= Start.
  66. // This implies that the offset is positive.
  67. // We need to subtract RangeLength from the offset, moving
  68. // the target closer to the symbol.
  69. // 2. The target is <= Start, but the actual symbol is >= End.
  70. // This implies that the offset is negative.
  71. // We need to add RangeLength to the offset, moving the
  72. // target closer to the symbol.
  73. // Case 1:
  74. if ((TargetLocation >= End) && (SymbolLocation <= Start))
  75. Location->Offset -= RangeLength;
  76. // Case 2:
  77. else if ((TargetLocation <= Start) && (SymbolLocation >= End))
  78. Location->Offset += RangeLength;
  79. }
  80. }
  81. }
  82. // Cut the specified range (the interval [Start,End)) out of
  83. // the specified section. All items within this range are removed. All relocs
  84. // refering to targets or relations behind End (taking Symbol and Offset,
  85. // but NOT FixedOffset, into account) are adjusted.
  86. void CutRange (SECTION *Section, OFFSET Start, OFFSET End)
  87. {
  88. PROGRAM *Program = Section->Parent;
  89. // Length of the range about to be cut.
  90. OFFSET RangeLength = End - Start;
  91. // Adjust the size.
  92. SIZE NewSize = Section->Size - RangeLength;
  93. if (Section->Data)
  94. {
  95. // Move the data.
  96. memmove (Section->Data + Start, Section->Data + End, Section->Size - End);
  97. }
  98. Section->Size = NewSize;
  99. // Adjust reloc targets and locations. We need to adjust relocs _targeting_
  100. // this section, so we need to check each section in the program.
  101. {
  102. SECTION *RelocSection;
  103. // For each section...
  104. for_each (RelocSection, Program->Sections)
  105. {
  106. RELOC *Reloc;
  107. // For each reloc...
  108. for_each (Reloc, RelocSection->Relocs)
  109. {
  110. // Only adjust relocs targeting this section.
  111. if (Reloc->Target.Symbol && (Reloc->Target.Symbol->Parent == Section))
  112. AdjustLocationForRangeCut (Reloc, &(Reloc->Target), Start, End);
  113. // Only adjust relations targeting this section.
  114. if (Reloc->Relation && Reloc->Relation->Symbol && (Reloc->Relation->Symbol->Parent == Section))
  115. AdjustLocationForRangeCut (Reloc, Reloc->Relation, Start, End);
  116. }
  117. }
  118. }
  119. // Now adjust symbol positions.
  120. {
  121. SYMBOL *Symbol;
  122. // For each symbol inside or behind the range...
  123. // (Ignore symbols at Start itself, they are not really inside the
  124. // range and cause spurious warnings. So start the search at Start + 1.)
  125. for (Symbol = FindSymbolAtPos (Section, Start + 1, TRUE); Symbol; Symbol = GetNext (Symbol))
  126. {
  127. // If the position was inside the range, put it at Start.
  128. if (Symbol->Location < End)
  129. {
  130. Symbol->Location = Start;
  131. Warning (GetFileName (Section, Symbol->Location), "Symbol `%s' at 0x%lX in section `%s' in a range which is being optimized away.", Symbol->Name, (unsigned long) Symbol->Location, Section->SectionSymbol->Name);
  132. }
  133. // If the position was behind the range, adjust it.
  134. else
  135. Symbol->Location -= RangeLength;
  136. }
  137. }
  138. // Now adjust the positions of all non-symbol items.
  139. // Define a macro to make moving items more simple.
  140. #define MoveItems(Type,Item,ItemName) \
  141. ({ \
  142. Type *Item; \
  143. for (Item = Find##Item##AtPos (Section, Start, TRUE); Item; Item = GetNext (Item)) \
  144. { \
  145. if (Item->Location + Item->Size > Start) \
  146. { \
  147. if (Item->Location < End) \
  148. { \
  149. Warning (GetFileName (Item->Parent, Item->Location), "%s at 0x%lX in section `%s' in a range which is being optimized away.", ItemName, (unsigned long) Item->Location, Section->SectionSymbol->Name); \
  150. if (Item->Location > Start) \
  151. Item->Location = Start; \
  152. } \
  153. else \
  154. Item->Location -= RangeLength; \
  155. } \
  156. } \
  157. })
  158. MoveItems (RELOC, Reloc, "Reloc");
  159. MoveItems (ROM_CALL, ROMCall, "ROM call");
  160. MoveItems (RAM_CALL, RAMCall, "RAM call");
  161. MoveItems (LIB_CALL, LibCall, "Library reference");
  162. #undef MoveItems
  163. }
  164. // Do the cleanup needed after cutting ranges in a section.
  165. void FinalizeRangeCutting (SECTION *Section)
  166. {
  167. if (Section->Data)
  168. {
  169. // Reduce the allocated size.
  170. I1 *NewData = realloc (Section->Data, Section->Size);
  171. // If NewData returns NULL, this means that either there was a weird "out
  172. // of memory" error (in this case, Section->Data is still valid), or
  173. // NewSize was 0. In the second case, it is all right to set Section->Data
  174. // to NULL.
  175. if (NewData || (!(Section->Size)))
  176. Section->Data = NewData;
  177. }
  178. }