[builtins] Pad embedded builtins with int3
This fills the padding between builtins in the embedded blob with a sequence of int3 instructions (ia32,x64). Drive-by: Unify code zapping. We can add better support for other architectures later. Bug: v8:6666 Change-Id: Ibcb120ec18a8062d7527e0c6fe5ca86869c0dad8 Reviewed-on: https://chromium-review.googlesource.com/1167050 Commit-Queue: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#54976}
This commit is contained in:
parent
e2fb86f804
commit
9c5f1abcf5
@ -3915,7 +3915,7 @@ void MinorMarkCompactCollector::MakeIterable(
|
||||
p->AddressToMarkbitIndex(free_start),
|
||||
p->AddressToMarkbitIndex(free_end));
|
||||
if (free_space_mode == ZAP_FREE_SPACE) {
|
||||
memset(reinterpret_cast<void*>(free_start), 0xCC, size);
|
||||
ZapCode(free_start, size);
|
||||
}
|
||||
p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size),
|
||||
ClearRecordedSlots::kNo);
|
||||
@ -3932,7 +3932,7 @@ void MinorMarkCompactCollector::MakeIterable(
|
||||
p->AddressToMarkbitIndex(free_start),
|
||||
p->AddressToMarkbitIndex(p->area_end()));
|
||||
if (free_space_mode == ZAP_FREE_SPACE) {
|
||||
memset(reinterpret_cast<void*>(free_start), 0xCC, size);
|
||||
ZapCode(free_start, size);
|
||||
}
|
||||
p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size),
|
||||
ClearRecordedSlots::kNo);
|
||||
|
@ -279,7 +279,7 @@ int Sweeper::RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
|
||||
CHECK_GT(free_end, free_start);
|
||||
size_t size = static_cast<size_t>(free_end - free_start);
|
||||
if (free_space_mode == ZAP_FREE_SPACE) {
|
||||
memset(reinterpret_cast<void*>(free_start), 0xCC, size);
|
||||
ZapCode(free_start, size);
|
||||
}
|
||||
if (free_list_mode == REBUILD_FREE_LIST) {
|
||||
freed_bytes = reinterpret_cast<PagedSpace*>(space)->Free(
|
||||
@ -319,7 +319,7 @@ int Sweeper::RawSweep(Page* p, FreeListRebuildingMode free_list_mode,
|
||||
CHECK_GT(p->area_end(), free_start);
|
||||
size_t size = static_cast<size_t>(p->area_end() - free_start);
|
||||
if (free_space_mode == ZAP_FREE_SPACE) {
|
||||
memset(reinterpret_cast<void*>(free_start), 0xCC, size);
|
||||
ZapCode(free_start, size);
|
||||
}
|
||||
if (free_list_mode == REBUILD_FREE_LIST) {
|
||||
freed_bytes = reinterpret_cast<PagedSpace*>(space)->Free(
|
||||
|
@ -330,9 +330,7 @@ Assembler::Assembler(const AssemblerOptions& options, void* buffer,
|
||||
// caller in which case we can't be sure it's okay to overwrite
|
||||
// existing code in it.
|
||||
#ifdef DEBUG
|
||||
if (own_buffer_) {
|
||||
memset(buffer_, 0xCC, buffer_size_); // int3
|
||||
}
|
||||
if (own_buffer_) ZapCode(reinterpret_cast<Address>(buffer_), buffer_size_);
|
||||
#endif
|
||||
|
||||
reloc_info_writer.Reposition(buffer_ + buffer_size_, pc_);
|
||||
@ -3194,7 +3192,7 @@ void Assembler::GrowBuffer() {
|
||||
// Clear the buffer in debug mode. Use 'int3' instructions to make
|
||||
// sure to get into problems if we ever run uninitialized code.
|
||||
#ifdef DEBUG
|
||||
memset(desc.buffer, 0xCC, desc.buffer_size);
|
||||
ZapCode(reinterpret_cast<Address>(desc.buffer), desc.buffer_size);
|
||||
#endif
|
||||
|
||||
// Copy the data.
|
||||
|
@ -406,7 +406,7 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
metadata[i].instructions_length = length;
|
||||
|
||||
// Align the start of each instruction stream.
|
||||
raw_data_size += RoundUp<kCodeAlignment>(length);
|
||||
raw_data_size += PadAndAlign(length);
|
||||
} else {
|
||||
metadata[i].instructions_offset = raw_data_size;
|
||||
}
|
||||
@ -418,8 +418,12 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
"If in doubt, ask jgruber@");
|
||||
|
||||
const uint32_t blob_size = RawDataOffset() + raw_data_size;
|
||||
uint8_t* blob = new uint8_t[blob_size];
|
||||
std::memset(blob, 0, blob_size);
|
||||
uint8_t* const blob = new uint8_t[blob_size];
|
||||
uint8_t* const raw_data_start = blob + RawDataOffset();
|
||||
|
||||
// Initially zap the entire blob, effectively padding the alignment area
|
||||
// between two builtins with int3's (on x64/ia32).
|
||||
ZapCode(reinterpret_cast<Address>(blob), blob_size);
|
||||
|
||||
// Write the metadata tables.
|
||||
DCHECK_EQ(MetadataSize(), sizeof(metadata[0]) * metadata.size());
|
||||
@ -430,7 +434,7 @@ EmbeddedData EmbeddedData::FromIsolate(Isolate* isolate) {
|
||||
if (!Builtins::IsIsolateIndependent(i)) continue;
|
||||
Code* code = builtins->builtin(i);
|
||||
uint32_t offset = metadata[i].instructions_offset;
|
||||
uint8_t* dst = blob + RawDataOffset() + offset;
|
||||
uint8_t* dst = raw_data_start + offset;
|
||||
DCHECK_LE(RawDataOffset() + offset + code->raw_instruction_size(),
|
||||
blob_size);
|
||||
std::memcpy(dst, reinterpret_cast<uint8_t*>(code->raw_instruction_start()),
|
||||
|
@ -96,7 +96,7 @@ class EmbeddedData final {
|
||||
|
||||
// Padded with kCodeAlignment.
|
||||
uint32_t PaddedInstructionSizeOfBuiltin(int i) const {
|
||||
return RoundUp<kCodeAlignment>(InstructionSizeOfBuiltin(i));
|
||||
return PadAndAlign(InstructionSizeOfBuiltin(i));
|
||||
}
|
||||
|
||||
size_t CreateHash() const;
|
||||
@ -130,7 +130,7 @@ class EmbeddedData final {
|
||||
return sizeof(struct Metadata) * kTableSize;
|
||||
}
|
||||
static constexpr uint32_t RawDataOffset() {
|
||||
return RoundUp<kCodeAlignment>(MetadataOffset() + MetadataSize());
|
||||
return PadAndAlign(MetadataOffset() + MetadataSize());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -141,6 +141,12 @@ class EmbeddedData final {
|
||||
}
|
||||
const uint8_t* RawData() const { return data_ + RawDataOffset(); }
|
||||
|
||||
static constexpr int PadAndAlign(int size) {
|
||||
// Ensure we have at least one byte trailing the actual builtin
|
||||
// instructions which we can later fill with int3.
|
||||
return RoundUp<kCodeAlignment>(size + 1);
|
||||
}
|
||||
|
||||
void PrintStatistics() const;
|
||||
|
||||
const uint8_t* data_;
|
||||
|
@ -1716,6 +1716,15 @@ class ThreadedList final {
|
||||
V8_EXPORT_PRIVATE bool PassesFilter(Vector<const char> name,
|
||||
Vector<const char> filter);
|
||||
|
||||
// Zap the specified area with a specific byte pattern. This currently defaults
|
||||
// to int3 on x64 and ia32. On other architectures this will produce unspecified
|
||||
// instruction sequences.
|
||||
// TODO(jgruber): Better support for other architectures.
|
||||
V8_INLINE void ZapCode(Address addr, size_t size_in_bytes) {
|
||||
static constexpr int kZapByte = 0xCC;
|
||||
std::memset(reinterpret_cast<void*>(addr), kZapByte, size_in_bytes);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -444,9 +444,7 @@ Assembler::Assembler(const AssemblerOptions& options, void* buffer,
|
||||
// caller in which case we can't be sure it's okay to overwrite
|
||||
// existing code in it.
|
||||
#ifdef DEBUG
|
||||
if (own_buffer_) {
|
||||
memset(buffer_, 0xCC, buffer_size_); // int3
|
||||
}
|
||||
if (own_buffer_) ZapCode(reinterpret_cast<Address>(buffer_), buffer_size_);
|
||||
#endif
|
||||
|
||||
ReserveCodeTargetSpace(100);
|
||||
@ -630,7 +628,7 @@ void Assembler::GrowBuffer() {
|
||||
// Clear the buffer in debug mode. Use 'int3' instructions to make
|
||||
// sure to get into problems if we ever run uninitialized code.
|
||||
#ifdef DEBUG
|
||||
memset(desc.buffer, 0xCC, desc.buffer_size);
|
||||
ZapCode(reinterpret_cast<Address>(desc.buffer), desc.buffer_size);
|
||||
#endif
|
||||
|
||||
// Copy the data.
|
||||
|
Loading…
Reference in New Issue
Block a user