1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// Section Manager for portable executables
5// Common to both Memory Only and Static (EXE making) code
6
7
8#ifndef PESectionMan_H
9#define PESectionMan_H
10
11#include "windef.h"
12
13#include "ceegen.h"
14#include "blobfetcher.h"
15
16class PESection;
17struct PESectionReloc;
18
19struct _IMAGE_SECTION_HEADER;
20
21class PESectionMan
22{
23public:
24
25 virtual ~PESectionMan() {}
26
27 HRESULT Init();
28 HRESULT Cleanup();
29
30 // Finds section with given name, or creates a new one
31 HRESULT getSectionCreate(
32 const char *name,
33 unsigned flags, // IMAGE_SCN_* flags. eg. IMAGE_SCN_CNT_INITIALIZED_DATA
34 PESection **section);
35
36 // Since we allocate, we must delete (Bug in VC, see knowledge base Q122675)
37 void sectionDestroy(PESection **section);
38
39 // Apply all the relocs for in memory conversion
40 HRESULT applyRelocs(CeeGenTokenMapper *pTokenMapper);
41
42 HRESULT cloneInstance(PESectionMan *destination);
43
44protected:
45
46 // Finds section with given name. returns 0 if not found
47 virtual PESection *getSection(const char *name);
48
49 // Create a new section
50 virtual HRESULT newSection(
51 const char *name,
52 PESection **section,
53 unsigned flags = sdNone,
54 unsigned estSize = 0x10000,
55 unsigned estRelocs = 1);
56
57 // Keep proctected & no accessors, so that derived class PEWriter
58 // is the ONLY one with access
59
60 PESection **sectStart;
61 PESection **sectCur;
62 PESection **sectEnd;
63}; // class PESectionMan
64
65/***************************************************************
66 * This represents a section of a ICeeFileGen. Multiple sections
67 * can be created with pointers to one another. These will
68 * automatically get fixed up when the ICeeFileGen is "baked".
69 *
70 * It is implemented using CBlobFetcher as a list of blobs.
71 * Thus it can grow arbitrarily. At the same time, it can appear
72 * as a flat consecutive piece of memory which can be indexed into
73 * using offsets.
74 */
75
76class PESection : public CeeSectionImpl {
77 public:
78 // bytes in this section at present
79 unsigned dataLen();
80
81 // Apply all the relocs for in memory conversion
82 HRESULT applyRelocs(CeeGenTokenMapper *pTokenMapper);
83
84 // get a block to write on (use instead of write to avoid copy)
85 char* getBlock(unsigned len, unsigned align=1);
86
87 // writes 'val' (which is offset into section 'relativeTo')
88 // and adds a relocation fixup for that section
89 void writeSectReloc(unsigned val, CeeSection& relativeTo,
90 CeeSectionRelocType reloc = srRelocHighLow,
91 CeeSectionRelocExtra *extra=0);
92
93 // Indicates that the DWORD at 'offset' in the current section should
94 // have the base of section 'relativeTo' added to it
95 HRESULT addSectReloc(unsigned offset, CeeSection& relativeTo,
96 CeeSectionRelocType reloc = srRelocHighLow,
97 CeeSectionRelocExtra *extra=0);
98
99 // If relativeTo is NULL, it is treated as a base reloc.
100 // ie. the value only needs to be fixed at load time if the module gets rebased.
101 HRESULT addSectReloc(unsigned offset, PESection *relativeTo,
102 CeeSectionRelocType reloc = srRelocHighLow,
103 CeeSectionRelocExtra *extra=0);
104
105 // Add a base reloc for the given offset in the current section
106 HRESULT addBaseReloc(unsigned offset, CeeSectionRelocType reloc = srRelocHighLow,
107 CeeSectionRelocExtra *extra = 0);
108
109 // section name
110 unsigned char *name() {
111 LIMITED_METHOD_CONTRACT;
112 return (unsigned char *) m_name;
113 }
114
115 // section flags
116 unsigned flags() {
117 LIMITED_METHOD_CONTRACT;
118 return m_flags;
119 }
120
121 // virtual base
122 unsigned getBaseRVA() {
123 LIMITED_METHOD_CONTRACT;
124 return m_baseRVA;
125 }
126
127 // return the dir entry for this section
128 int getDirEntry() {
129 LIMITED_METHOD_CONTRACT;
130 return dirEntry;
131 }
132 // this section will be directory entry 'num'
133 HRESULT directoryEntry(unsigned num);
134
135 // Indexes offset as if this were an array
136 // Returns a pointer into the correct blob
137 virtual char * computePointer(unsigned offset) const;
138
139 // Checks to see if pointer is in section
140 virtual BOOL containsPointer(__in char *ptr) const;
141
142 // Given a pointer pointing into this section,
143 // computes an offset as if this were an array
144 virtual unsigned computeOffset(__in char *ptr) const;
145
146 // Make 'destination' a copy of the current PESection
147 HRESULT cloneInstance(PESection *destination);
148
149 // Cause the section to allocate memory in smaller chunks
150 void SetInitialGrowth(unsigned growth);
151
152 virtual ~PESection();
153private:
154
155 // purposely not defined,
156 PESection();
157
158 // purposely not defined,
159 PESection(const PESection&);
160
161 // purposely not defined,
162 PESection& operator=(const PESection& x);
163
164 // this dir entry points to this section
165 int dirEntry;
166
167protected:
168 friend class PEWriter;
169 friend class PEWriterSection;
170 friend class PESectionMan;
171
172 PESection(const char* name, unsigned flags,
173 unsigned estSize, unsigned estRelocs);
174
175 // Blob fetcher handles getBlock() and fetching binary chunks.
176 CBlobFetcher m_blobFetcher;
177
178 PESectionReloc* m_relocStart;
179 PESectionReloc* m_relocCur;
180 PESectionReloc* m_relocEnd;
181
182 // These will be set while baking (finalizing) the file
183 unsigned m_baseRVA; // RVA into the file of this section.
184 unsigned m_filePos; // Start offset into the file (treated as a data image)
185 unsigned m_filePad; // Padding added to the end of the section for alignment
186
187 char m_name[8+6]; // extra room for digits
188 unsigned m_flags;
189
190 struct _IMAGE_SECTION_HEADER* m_header; // Corresponding header. Assigned after link()
191};
192
193/***************************************************************/
194/* implementation section */
195
196inline HRESULT PESection::directoryEntry(unsigned num) {
197 WRAPPER_NO_CONTRACT;
198 TESTANDRETURN(num < 16, E_INVALIDARG);
199 dirEntry = num;
200 return S_OK;
201}
202
203// This remembers the location where a reloc needs to be applied.
204// It is relative to the contents of a PESection
205
206struct PESectionReloc {
207 CeeSectionRelocType type; // type of reloc
208 unsigned offset; // offset within the current PESection where the reloc is to be applied
209 CeeSectionRelocExtra extra;
210 PESection* section; // target PESection. NULL implies that the target is a fixed address outside the module
211};
212
213#endif // #define PESectionMan_H
214