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 <algorithm>
18 :
19 : #include "base/strings/string_util.h"
20 : #include "syzygy/common/align.h"
21 : #include "syzygy/pe/pe_utils.h"
22 :
23 : namespace pe {
24 :
25 : PECoffImageLayoutBuilder::PECoffImageLayoutBuilder(ImageLayout* image_layout)
26 : : image_layout_(image_layout),
27 : padding_(0),
28 : code_alignment_(1),
29 : section_alignment_(1),
30 E : file_alignment_(1) {
31 E : DCHECK(image_layout != NULL);
32 E : DCHECK_EQ(0u, image_layout->blocks.address_space_impl().size());
33 E : DCHECK_EQ(0u, image_layout->sections.size());
34 E : }
35 :
36 : void PECoffImageLayoutBuilder::Init(size_t section_alignment,
37 E : size_t file_alignment) {
38 E : DCHECK_LT(0u, section_alignment);
39 E : DCHECK_LT(0u, file_alignment);
40 E : DCHECK_LE(file_alignment, section_alignment);
41 E : DCHECK_EQ(0u, section_alignment % file_alignment);
42 :
43 E : section_alignment_ = section_alignment;
44 E : file_alignment_ = file_alignment;
45 E : }
46 :
47 : bool PECoffImageLayoutBuilder::OpenSection(const char* name,
48 E : uint32 characteristics) {
49 E : DCHECK(name != NULL);
50 :
51 : // If we're already in a section, close it.
52 E : if (section_start_.value() != 0)
53 i : CloseSection();
54 :
55 : // Align to the start of the next section.
56 E : DCHECK_LT(0u, cursor_.value());
57 E : cursor_ = cursor_.AlignUp(section_alignment_);
58 :
59 : // Remember the start of the section and reset the initialized data cursors.
60 E : DCHECK_EQ(0u, section_start_.value());
61 E : DCHECK_EQ(0u, section_auto_init_end_.value());
62 E : DCHECK_EQ(0u, section_init_end_.value());
63 E : section_start_ = cursor_;
64 E : section_auto_init_end_ = cursor_;
65 E : section_init_end_ = cursor_;
66 :
67 : // Create a section.
68 E : ImageLayout::SectionInfo section_info;
69 E : section_info.name = name;
70 E : section_info.addr = section_start_;
71 E : section_info.size = 0;
72 E : section_info.data_size = 0;
73 E : section_info.characteristics = characteristics;
74 E : image_layout_->sections.push_back(section_info);
75 :
76 E : return true;
77 E : }
78 :
79 E : bool PECoffImageLayoutBuilder::OpenSection(const BlockGraph::Section& section) {
80 E : return OpenSection(section.name().c_str(), section.characteristics());
81 E : }
82 :
83 E : bool PECoffImageLayoutBuilder::LayoutBlock(BlockGraph::Block* block) {
84 E : DCHECK(block != NULL);
85 E : return LayoutBlock(block->alignment(), block);
86 E : }
87 :
88 : bool PECoffImageLayoutBuilder::LayoutBlock(size_t alignment,
89 E : BlockGraph::Block* block) {
90 E : DCHECK_LT(0u, alignment);
91 E : DCHECK(block != NULL);
92 E : DCHECK_NE(0u, section_start_.value());
93 :
94 : // We don't need to apply inter-block padding to the first block.
95 E : if (padding_ > 0 && cursor_ > section_start_) {
96 : // Apply the bigger padding.
97 E : cursor_ += std::max(block->padding_before(), padding_);
98 E : } else {
99 : // Per-block padding needs to be applied to the first block as well.
100 E : cursor_ += block->padding_before();
101 : }
102 :
103 : // Keep the larger alignment.
104 E : if (block->type() == BlockGraph::CODE_BLOCK && alignment < code_alignment_)
105 E : alignment = code_alignment_;
106 :
107 : // Align at the proper offset.
108 : {
109 E : cursor_ += block->alignment_offset();
110 E : cursor_ = cursor_.AlignUp(alignment);
111 E : cursor_ -= block->alignment_offset();
112 : }
113 :
114 : // If we have explicit data, advance the explicit data cursor.
115 E : if (block->data_size() > 0)
116 E : section_auto_init_end_ = cursor_ + block->data_size();
117 :
118 : // This advances the cursor for us.
119 E : if (!LayoutBlockImpl(block))
120 i : return false;
121 :
122 E : return true;
123 E : }
124 :
125 : void PECoffImageLayoutBuilder::CloseExplicitSectionData() {
126 : DCHECK_NE(0u, section_start_.value());
127 : section_init_end_ = cursor_;
128 : }
129 :
130 E : bool PECoffImageLayoutBuilder::CloseSection() {
131 E : DCHECK_NE(0u, section_start_.value());
132 E : DCHECK_LT(0u, image_layout_->sections.size());
133 :
134 E : size_t section_size = cursor_ - section_start_;
135 :
136 : // If provided use the explicit initialized data size, otherwise use the
137 : // automatic one.
138 E : size_t init_size = 0;
139 E : if (section_init_end_ > cursor_) {
140 i : if (section_auto_init_end_ > section_init_end_) {
141 i : LOG(ERROR) << "Blocks with initialized data lay beyond explicitly "
142 : "specified end of initialized data.";
143 i : return false;
144 : }
145 i : init_size = section_init_end_ - section_start_;
146 i : } else {
147 E : init_size = section_auto_init_end_ - section_start_;
148 : }
149 :
150 : // A section must have *some* presence in the file.
151 E : if (init_size == 0)
152 E : init_size = 1;
153 :
154 E : init_size = common::AlignUp(init_size, file_alignment_);
155 :
156 E : ImageLayout::SectionInfo& section_info = image_layout_->sections.back();
157 E : section_info.size = section_size;
158 E : section_info.data_size = init_size;
159 :
160 E : if (cursor_ < section_start_ + init_size)
161 E : cursor_ = section_start_ + init_size;
162 :
163 E : section_start_.set_value(0);
164 E : section_auto_init_end_.set_value(0);
165 E : section_init_end_.set_value(0);
166 :
167 E : return true;
168 E : }
169 :
170 : // Lays out a block at the current cursor location.
171 E : bool PECoffImageLayoutBuilder::LayoutBlockImpl(BlockGraph::Block* block) {
172 E : DCHECK(block != NULL);
173 E : if (!image_layout_->blocks.InsertBlock(cursor_, block)) {
174 i : LOG(ERROR) << "InsertBlock failed for block (id=" << block->id()
175 : << ", name=\"" << block->name() << "\").";
176 i : return false;
177 : }
178 E : cursor_ += block->size();
179 E : return true;
180 E : }
181 :
182 : } // namespace pe
|