1 : // Copyright 2013 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/pe/pe_coff_image_layout_builder.h"
16 :
17 : #include "base/string_util.h"
18 : #include "syzygy/common/align.h"
19 : #include "syzygy/pe/pe_utils.h"
20 :
21 : namespace pe {
22 :
23 : PECoffImageLayoutBuilder::PECoffImageLayoutBuilder(ImageLayout* image_layout)
24 : : image_layout_(image_layout),
25 : padding_(0),
26 : code_alignment_(1),
27 : section_alignment_(1),
28 E : file_alignment_(1) {
29 E : DCHECK(image_layout != NULL);
30 E : DCHECK_EQ(0u, image_layout->blocks.address_space_impl().size());
31 E : DCHECK_EQ(0u, image_layout->sections.size());
32 E : }
33 :
34 : void PECoffImageLayoutBuilder::Init(size_t section_alignment,
35 E : size_t file_alignment) {
36 E : DCHECK_LT(0u, section_alignment);
37 E : DCHECK_LT(0u, file_alignment);
38 E : DCHECK_LE(file_alignment, section_alignment);
39 E : DCHECK_EQ(0u, section_alignment % file_alignment);
40 :
41 E : section_alignment_ = section_alignment;
42 E : file_alignment_ = file_alignment;
43 E : }
44 :
45 : bool PECoffImageLayoutBuilder::OpenSection(const char* name,
46 E : uint32 characteristics) {
47 E : DCHECK(name != NULL);
48 :
49 : // If we're already in a section, close it.
50 E : if (section_start_.value() != 0)
51 i : CloseSection();
52 :
53 : // Align to the start of the next section.
54 E : DCHECK_LT(0u, cursor_.value());
55 E : cursor_ = cursor_.AlignUp(section_alignment_);
56 :
57 : // Remember the start of the section and reset the initialized data cursors.
58 E : DCHECK_EQ(0u, section_start_.value());
59 E : DCHECK_EQ(0u, section_auto_init_end_.value());
60 E : DCHECK_EQ(0u, section_init_end_.value());
61 E : section_start_ = cursor_;
62 E : section_auto_init_end_ = cursor_;
63 E : section_init_end_ = cursor_;
64 :
65 : // Create a section.
66 E : ImageLayout::SectionInfo section_info;
67 E : section_info.name = name;
68 E : section_info.addr = section_start_;
69 E : section_info.size = 0;
70 E : section_info.data_size = 0;
71 E : section_info.characteristics = characteristics;
72 E : image_layout_->sections.push_back(section_info);
73 :
74 E : return true;
75 E : }
76 :
77 E : bool PECoffImageLayoutBuilder::OpenSection(const BlockGraph::Section& section) {
78 E : return OpenSection(section.name().c_str(), section.characteristics());
79 E : }
80 :
81 E : bool PECoffImageLayoutBuilder::LayoutBlock(BlockGraph::Block* block) {
82 E : DCHECK(block != NULL);
83 E : return LayoutBlock(block->alignment(), block);
84 E : }
85 :
86 : bool PECoffImageLayoutBuilder::LayoutBlock(size_t alignment,
87 E : BlockGraph::Block* block) {
88 E : DCHECK_LT(0u, alignment);
89 E : DCHECK(block != NULL);
90 E : DCHECK_NE(0u, section_start_.value());
91 :
92 : // If this is not the first block of the section and we have padding, then
93 : // output the padding.
94 E : if (padding_ > 0 && cursor_ > section_start_)
95 E : cursor_ += padding_;
96 :
97 : // Keep the larger alignment.
98 E : if (block->type() == BlockGraph::CODE_BLOCK && alignment < code_alignment_)
99 E : alignment = code_alignment_;
100 E : cursor_ = cursor_.AlignUp(alignment);
101 :
102 : // If we have explicit data, advance the explicit data cursor.
103 E : if (block->data_size() > 0)
104 E : section_auto_init_end_ = cursor_ + block->data_size();
105 :
106 : // This advances the cursor for us.
107 E : if (!LayoutBlockImpl(block))
108 i : return false;
109 :
110 E : return true;
111 E : }
112 :
113 : void PECoffImageLayoutBuilder::CloseExplicitSectionData() {
114 : DCHECK_NE(0u, section_start_.value());
115 : section_init_end_ = cursor_;
116 : }
117 :
118 E : bool PECoffImageLayoutBuilder::CloseSection() {
119 E : DCHECK_NE(0u, section_start_.value());
120 E : DCHECK_LT(0u, image_layout_->sections.size());
121 :
122 E : size_t section_size = cursor_ - section_start_;
123 :
124 : // If provided use the explicit initialized data size, otherwise use the
125 : // automatic one.
126 E : size_t init_size = 0;
127 E : if (section_init_end_ > cursor_) {
128 i : if (section_auto_init_end_ > section_init_end_) {
129 i : LOG(ERROR) << "Blocks with initialized data lay beyond explicitly "
130 : "specified end of initialized data.";
131 i : return false;
132 : }
133 i : init_size = section_init_end_ - section_start_;
134 i : } else {
135 E : init_size = section_auto_init_end_ - section_start_;
136 : }
137 :
138 : // A section must have *some* presence in the file.
139 E : if (init_size == 0)
140 E : init_size = 1;
141 :
142 E : init_size = common::AlignUp(init_size, file_alignment_);
143 :
144 E : ImageLayout::SectionInfo& section_info = image_layout_->sections.back();
145 E : section_info.size = section_size;
146 E : section_info.data_size = init_size;
147 :
148 E : if (cursor_ < section_start_ + init_size)
149 E : cursor_ = section_start_ + init_size;
150 :
151 E : section_start_.set_value(0);
152 E : section_auto_init_end_.set_value(0);
153 E : section_init_end_.set_value(0);
154 :
155 E : return true;
156 E : }
157 :
158 : // Lays out a block at the current cursor location.
159 E : bool PECoffImageLayoutBuilder::LayoutBlockImpl(BlockGraph::Block* block) {
160 E : DCHECK(block != NULL);
161 E : if (!image_layout_->blocks.InsertBlock(cursor_, block)) {
162 i : LOG(ERROR) << "InsertBlock failed for block (id=" << block->id()
163 : << ", name=\"" << block->name() << "\").";
164 i : return false;
165 : }
166 E : cursor_ += block->size();
167 E : return true;
168 E : }
169 :
170 : } // namespace pe
|