summaryrefslogtreecommitdiff
path: root/src/inc/pesectionman.h
blob: f031ca34bfb92a505b22f5c7c0d4c5263ab172d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// Section Manager for portable executables
// Common to both Memory Only and Static (EXE making) code


#ifndef PESectionMan_H
#define PESectionMan_H

#include "windef.h"

#include "ceegen.h"
#include "blobfetcher.h"

class PESection;
struct PESectionReloc;

struct _IMAGE_SECTION_HEADER;

class PESectionMan
{
public:

    virtual ~PESectionMan() {}

    HRESULT Init();
    HRESULT Cleanup();

    // Finds section with given name, or creates a new one
    HRESULT getSectionCreate(
        const char *name,
        unsigned flags, // IMAGE_SCN_* flags. eg. IMAGE_SCN_CNT_INITIALIZED_DATA
        PESection **section);

    // Since we allocate, we must delete (Bug in VC, see knowledge base Q122675)
    void sectionDestroy(PESection **section);

    // Apply all the relocs for in memory conversion
    HRESULT applyRelocs(CeeGenTokenMapper *pTokenMapper);

    HRESULT cloneInstance(PESectionMan *destination);

protected:
    
    // Finds section with given name.  returns 0 if not found
    virtual PESection *getSection(const char *name);
    
    // Create a new section
    virtual HRESULT newSection(
        const char *name, 
        PESection **section,
        unsigned    flags     = sdNone, 
        unsigned    estSize   = 0x10000, 
        unsigned    estRelocs = 1);
    
    // Keep proctected & no accessors, so that derived class PEWriter 
    // is the ONLY one with access
    
    PESection **sectStart;
    PESection **sectCur;
    PESection **sectEnd;
};  // class PESectionMan

/***************************************************************
 * This represents a section of a ICeeFileGen. Multiple sections
 * can be created with pointers to one another. These will
 * automatically get fixed up when the ICeeFileGen is "baked".
 *
 * It is implemented using CBlobFetcher as a list of blobs.
 * Thus it can grow arbitrarily. At the same time, it can appear
 * as a flat consecutive piece of memory which can be indexed into
 * using offsets.
 */
 
class PESection : public CeeSectionImpl {
  public:
    // bytes in this section at present
    unsigned dataLen();     

    // Apply all the relocs for in memory conversion
    HRESULT applyRelocs(CeeGenTokenMapper *pTokenMapper);
    
    // get a block to write on (use instead of write to avoid copy)
    char* getBlock(unsigned len, unsigned align=1);

    // writes 'val' (which is offset into section 'relativeTo')
    // and adds a relocation fixup for that section
    void writeSectReloc(unsigned val, CeeSection& relativeTo, 
                CeeSectionRelocType reloc = srRelocHighLow,
                CeeSectionRelocExtra *extra=0);
                        
    // Indicates that the DWORD at 'offset' in the current section should
    // have the base of section 'relativeTo' added to it
    HRESULT addSectReloc(unsigned offset, CeeSection& relativeTo, 
                            CeeSectionRelocType reloc = srRelocHighLow,
                            CeeSectionRelocExtra *extra=0);

    // If relativeTo is NULL, it is treated as a base reloc.
    // ie. the value only needs to be fixed at load time if the module gets rebased.
    HRESULT addSectReloc(unsigned offset, PESection *relativeTo, 
                            CeeSectionRelocType reloc = srRelocHighLow,
                            CeeSectionRelocExtra *extra=0);

    // Add a base reloc for the given offset in the current section
    HRESULT addBaseReloc(unsigned offset, CeeSectionRelocType reloc = srRelocHighLow, 
                            CeeSectionRelocExtra *extra = 0);

    // section name
    unsigned char *name() {
        LIMITED_METHOD_CONTRACT;
        return (unsigned char *) m_name;
    }

    // section flags
    unsigned flags() {
        LIMITED_METHOD_CONTRACT;
        return m_flags;
    }

    // virtual base
    unsigned getBaseRVA() {
        LIMITED_METHOD_CONTRACT;
        return m_baseRVA;
    }

    // return the dir entry for this section
    int getDirEntry() {
        LIMITED_METHOD_CONTRACT;
        return dirEntry;
    }
    // this section will be directory entry 'num'
    HRESULT directoryEntry(unsigned num);

    // Indexes offset as if this were an array
    // Returns a pointer into the correct blob
    virtual char * computePointer(unsigned offset) const;

    // Checks to see if pointer is in section
    virtual BOOL containsPointer(__in char *ptr) const;

    // Given a pointer pointing into this section,
    // computes an offset as if this were an array
    virtual unsigned computeOffset(__in char *ptr) const;

    // Make 'destination' a copy of the current PESection
    HRESULT cloneInstance(PESection *destination);

    // Cause the section to allocate memory in smaller chunks
    void SetInitialGrowth(unsigned growth);

    virtual ~PESection();
private:

    // purposely not defined, 
    PESection();            

    // purposely not defined,
    PESection(const PESection&);                     

    // purposely not defined,
    PESection& operator=(const PESection& x);        

    // this dir entry points to this section
    int dirEntry;           

protected:
    friend class PEWriter;
    friend class PEWriterSection;
    friend class PESectionMan;

    PESection(const char* name, unsigned flags, 
              unsigned estSize, unsigned estRelocs);

    // Blob fetcher handles getBlock() and fetching binary chunks.
    CBlobFetcher m_blobFetcher;
    
    PESectionReloc* m_relocStart;
    PESectionReloc* m_relocCur;
    PESectionReloc* m_relocEnd;

    // These will be set while baking (finalizing) the file
    unsigned    m_baseRVA;      // RVA into the file of this section.
    unsigned    m_filePos;      // Start offset into the file (treated as a data image)
    unsigned    m_filePad;      // Padding added to the end of the section for alignment
    
    char        m_name[8+6];    // extra room for digits
    unsigned    m_flags;

    struct _IMAGE_SECTION_HEADER* m_header; // Corresponding header. Assigned after link()
};

/***************************************************************/
/* implementation section */

inline HRESULT PESection::directoryEntry(unsigned num) { 
    WRAPPER_NO_CONTRACT;
    TESTANDRETURN(num < 16, E_INVALIDARG);
    dirEntry = num; 
    return S_OK;
}

// This remembers the location where a reloc needs to be applied.
// It is relative to the contents of a PESection

struct PESectionReloc {
    CeeSectionRelocType     type;       // type of reloc
    unsigned                offset;     // offset within the current PESection where the reloc is to be applied
    CeeSectionRelocExtra    extra;
    PESection*              section;    // target PESection. NULL implies that the target is a fixed address outside the module
};

#endif // #define PESectionMan_H