1 /* 2 * Copyright (C) 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #ifndef LinkBuffer_h 27 #define LinkBuffer_h 28 29 #include <wtf/Platform.h> 30 31 #if ENABLE(ASSEMBLER) 32 33 #include <MacroAssembler.h> 34 #include <wtf/Noncopyable.h> 35 36 namespace JSC { 37 38 // LinkBuffer: 39 // 40 // This class assists in linking code generated by the macro assembler, once code generation 41 // has been completed, and the code has been copied to is final location in memory. At this 42 // time pointers to labels within the code may be resolved, and relative offsets to external 43 // addresses may be fixed. 44 // 45 // Specifically: 46 // * Jump objects may be linked to external targets, 47 // * The address of Jump objects may taken, such that it can later be relinked. 48 // * The return address of a Call may be acquired. 49 // * The address of a Label pointing into the code may be resolved. 50 // * The value referenced by a DataLabel may be set. 51 // 52 class LinkBuffer : public Noncopyable { 53 typedef MacroAssemblerCodeRef CodeRef; 54 typedef MacroAssembler::Label Label; 55 typedef MacroAssembler::Jump Jump; 56 typedef MacroAssembler::JumpList JumpList; 57 typedef MacroAssembler::Call Call; 58 typedef MacroAssembler::DataLabel32 DataLabel32; 59 typedef MacroAssembler::DataLabelPtr DataLabelPtr; 60 61 public: 62 // Note: Initialization sequence is significant, since executablePool is a PassRefPtr. 63 // First, executablePool is copied into m_executablePool, then the initialization of 64 // m_code uses m_executablePool, *not* executablePool, since this is no longer valid. LinkBuffer(MacroAssembler * masm,PassRefPtr<ExecutablePool> executablePool)65 LinkBuffer(MacroAssembler* masm, PassRefPtr<ExecutablePool> executablePool) 66 : m_executablePool(executablePool) 67 , m_code(masm->m_assembler.executableCopy(m_executablePool.get())) 68 , m_size(masm->m_assembler.size()) 69 #ifndef NDEBUG 70 , m_completed(false) 71 #endif 72 { 73 } 74 ~LinkBuffer()75 ~LinkBuffer() 76 { 77 ASSERT(m_completed); 78 } 79 80 // These methods are used to link or set values at code generation time. 81 link(Call call,FunctionPtr function)82 void link(Call call, FunctionPtr function) 83 { 84 ASSERT(call.isFlagSet(Call::Linkable)); 85 MacroAssembler::linkCall(code(), call, function); 86 } 87 link(Jump jump,CodeLocationLabel label)88 void link(Jump jump, CodeLocationLabel label) 89 { 90 MacroAssembler::linkJump(code(), jump, label); 91 } 92 link(JumpList list,CodeLocationLabel label)93 void link(JumpList list, CodeLocationLabel label) 94 { 95 for (unsigned i = 0; i < list.m_jumps.size(); ++i) 96 MacroAssembler::linkJump(code(), list.m_jumps[i], label); 97 } 98 patch(DataLabelPtr label,void * value)99 void patch(DataLabelPtr label, void* value) 100 { 101 MacroAssembler::linkPointer(code(), label.m_label, value); 102 } 103 patch(DataLabelPtr label,CodeLocationLabel value)104 void patch(DataLabelPtr label, CodeLocationLabel value) 105 { 106 MacroAssembler::linkPointer(code(), label.m_label, value.executableAddress()); 107 } 108 109 // These methods are used to obtain handles to allow the code to be relinked / repatched later. 110 locationOf(Call call)111 CodeLocationCall locationOf(Call call) 112 { 113 ASSERT(call.isFlagSet(Call::Linkable)); 114 ASSERT(!call.isFlagSet(Call::Near)); 115 return CodeLocationCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); 116 } 117 locationOfNearCall(Call call)118 CodeLocationNearCall locationOfNearCall(Call call) 119 { 120 ASSERT(call.isFlagSet(Call::Linkable)); 121 ASSERT(call.isFlagSet(Call::Near)); 122 return CodeLocationNearCall(MacroAssembler::getLinkerAddress(code(), call.m_jmp)); 123 } 124 locationOf(Label label)125 CodeLocationLabel locationOf(Label label) 126 { 127 return CodeLocationLabel(MacroAssembler::getLinkerAddress(code(), label.m_label)); 128 } 129 locationOf(DataLabelPtr label)130 CodeLocationDataLabelPtr locationOf(DataLabelPtr label) 131 { 132 return CodeLocationDataLabelPtr(MacroAssembler::getLinkerAddress(code(), label.m_label)); 133 } 134 locationOf(DataLabel32 label)135 CodeLocationDataLabel32 locationOf(DataLabel32 label) 136 { 137 return CodeLocationDataLabel32(MacroAssembler::getLinkerAddress(code(), label.m_label)); 138 } 139 140 // This method obtains the return address of the call, given as an offset from 141 // the start of the code. returnAddressOffset(Call call)142 unsigned returnAddressOffset(Call call) 143 { 144 return MacroAssembler::getLinkerCallReturnOffset(call); 145 } 146 147 // Upon completion of all patching either 'finalizeCode()' or 'finalizeCodeAddendum()' should be called 148 // once to complete generation of the code. 'finalizeCode()' is suited to situations 149 // where the executable pool must also be retained, the lighter-weight 'finalizeCodeAddendum()' is 150 // suited to adding to an existing allocation. finalizeCode()151 CodeRef finalizeCode() 152 { 153 performFinalization(); 154 155 return CodeRef(m_code, m_executablePool, m_size); 156 } finalizeCodeAddendum()157 CodeLocationLabel finalizeCodeAddendum() 158 { 159 performFinalization(); 160 161 return CodeLocationLabel(code()); 162 } 163 164 private: 165 // Keep this private! - the underlying code should only be obtained externally via 166 // finalizeCode() or finalizeCodeAddendum(). code()167 void* code() 168 { 169 return m_code; 170 } 171 performFinalization()172 void performFinalization() 173 { 174 #ifndef NDEBUG 175 ASSERT(!m_completed); 176 m_completed = true; 177 #endif 178 179 ExecutableAllocator::makeExecutable(code(), m_size); 180 ExecutableAllocator::cacheFlush(code(), m_size); 181 } 182 183 RefPtr<ExecutablePool> m_executablePool; 184 void* m_code; 185 size_t m_size; 186 #ifndef NDEBUG 187 bool m_completed; 188 #endif 189 }; 190 191 } // namespace JSC 192 193 #endif // ENABLE(ASSEMBLER) 194 195 #endif // LinkBuffer_h 196