-#ifdef __native_client_codegen__
-
-/* Keep track of instruction "depth", that is, the level of sub-instruction */
-/* for any given instruction. For instance, amd64_call_reg resolves to */
-/* amd64_call_reg_internal, which uses amd64_alu_* macros, etc. */
-/* We only want to force bundle alignment for the top level instruction, */
-/* so NaCl pseudo-instructions can be implemented with sub instructions. */
-static MonoNativeTlsKey nacl_instruction_depth;
-
-static MonoNativeTlsKey nacl_rex_tag;
-static MonoNativeTlsKey nacl_legacy_prefix_tag;
-
-void
-amd64_nacl_clear_legacy_prefix_tag ()
-{
- mono_native_tls_set_value (nacl_legacy_prefix_tag, NULL);
-}
-
-void
-amd64_nacl_tag_legacy_prefix (guint8* code)
-{
- if (mono_native_tls_get_value (nacl_legacy_prefix_tag) == NULL)
- mono_native_tls_set_value (nacl_legacy_prefix_tag, code);
-}
-
-void
-amd64_nacl_tag_rex (guint8* code)
-{
- mono_native_tls_set_value (nacl_rex_tag, code);
-}
-
-guint8*
-amd64_nacl_get_legacy_prefix_tag ()
-{
- return (guint8*)mono_native_tls_get_value (nacl_legacy_prefix_tag);
-}
-
-guint8*
-amd64_nacl_get_rex_tag ()
-{
- return (guint8*)mono_native_tls_get_value (nacl_rex_tag);
-}
-
-/* Increment the instruction "depth" described above */
-void
-amd64_nacl_instruction_pre ()
-{
- intptr_t depth = (intptr_t) mono_native_tls_get_value (nacl_instruction_depth);
- depth++;
- mono_native_tls_set_value (nacl_instruction_depth, (gpointer)depth);
-}
-
-/* amd64_nacl_instruction_post: Decrement instruction "depth", force bundle */
-/* alignment if depth == 0 (top level instruction) */
-/* IN: start, end pointers to instruction beginning and end */
-/* OUT: start, end pointers to beginning and end after possible alignment */
-/* GLOBALS: nacl_instruction_depth defined above */
-void
-amd64_nacl_instruction_post (guint8 **start, guint8 **end)
-{
- intptr_t depth = (intptr_t) mono_native_tls_get_value (nacl_instruction_depth);
- depth--;
- mono_native_tls_set_value (nacl_instruction_depth, (void*)depth);
-
- g_assert ( depth >= 0 );
- if (depth == 0) {
- uintptr_t space_in_block;
- uintptr_t instlen;
- guint8 *prefix = amd64_nacl_get_legacy_prefix_tag ();
- /* if legacy prefix is present, and if it was emitted before */
- /* the start of the instruction sequence, adjust the start */
- if (prefix != NULL && prefix < *start) {
- g_assert (*start - prefix <= 3);/* only 3 are allowed */
- *start = prefix;
- }
- space_in_block = kNaClAlignment - ((uintptr_t)(*start) & kNaClAlignmentMask);
- instlen = (uintptr_t)(*end - *start);
- /* Only check for instructions which are less than */
- /* kNaClAlignment. The only instructions that should ever */
- /* be that long are call sequences, which are already */
- /* padded out to align the return to the next bundle. */
- if (instlen > space_in_block && instlen < kNaClAlignment) {
- const size_t MAX_NACL_INST_LENGTH = kNaClAlignment;
- guint8 copy_of_instruction[MAX_NACL_INST_LENGTH];
- const size_t length = (size_t)((*end)-(*start));
- g_assert (length < MAX_NACL_INST_LENGTH);
-
- memcpy (copy_of_instruction, *start, length);
- *start = mono_arch_nacl_pad (*start, space_in_block);
- memcpy (*start, copy_of_instruction, length);
- *end = *start + length;
- }
- amd64_nacl_clear_legacy_prefix_tag ();
- amd64_nacl_tag_rex (NULL);
- }
-}
-
-/* amd64_nacl_membase_handler: ensure all access to memory of the form */
-/* OFFSET(%rXX) is sandboxed. For allowable base registers %rip, %rbp, */
-/* %rsp, and %r15, emit the membase as usual. For all other registers, */
-/* make sure the upper 32-bits are cleared, and use that register in the */
-/* index field of a new address of this form: OFFSET(%r15,%eXX,1) */
-/* IN: code */
-/* pointer to current instruction stream (in the */
-/* middle of an instruction, after opcode is emitted) */
-/* basereg/offset/dreg */
-/* operands of normal membase address */
-/* OUT: code */
-/* pointer to the end of the membase/memindex emit */
-/* GLOBALS: nacl_rex_tag */
-/* position in instruction stream that rex prefix was emitted */
-/* nacl_legacy_prefix_tag */
-/* (possibly NULL) position in instruction of legacy x86 prefix */
-void
-amd64_nacl_membase_handler (guint8** code, gint8 basereg, gint32 offset, gint8 dreg)
-{
- gint8 true_basereg = basereg;
-
- /* Cache these values, they might change */
- /* as new instructions are emitted below. */
- guint8* rex_tag = amd64_nacl_get_rex_tag ();
- guint8* legacy_prefix_tag = amd64_nacl_get_legacy_prefix_tag ();
-
- /* 'basereg' is given masked to 0x7 at this point, so check */
- /* the rex prefix to see if this is an extended register. */
- if ((rex_tag != NULL) && IS_REX(*rex_tag) && (*rex_tag & AMD64_REX_B)) {
- true_basereg |= 0x8;
- }
-
-#define X86_LEA_OPCODE (0x8D)
-
- if (!amd64_is_valid_nacl_base (true_basereg) && (*(*code-1) != X86_LEA_OPCODE)) {
- guint8* old_instruction_start;
-
- /* This will hold the 'mov %eXX, %eXX' that clears the upper */
- /* 32-bits of the old base register (new index register) */
- guint8 buf[32];
- guint8* buf_ptr = buf;
- size_t insert_len;
-
- g_assert (rex_tag != NULL);
-
- if (IS_REX(*rex_tag)) {
- /* The old rex.B should be the new rex.X */
- if (*rex_tag & AMD64_REX_B) {
- *rex_tag |= AMD64_REX_X;
- }
- /* Since our new base is %r15 set rex.B */
- *rex_tag |= AMD64_REX_B;
- } else {
- /* Shift the instruction by one byte */
- /* so we can insert a rex prefix */
- memmove (rex_tag + 1, rex_tag, (size_t)(*code - rex_tag));
- *code += 1;
- /* New rex prefix only needs rex.B for %r15 base */
- *rex_tag = AMD64_REX(AMD64_REX_B);
- }
-
- if (legacy_prefix_tag) {
- old_instruction_start = legacy_prefix_tag;
- } else {
- old_instruction_start = rex_tag;
- }
-
- /* Clears the upper 32-bits of the previous base register */
- amd64_mov_reg_reg_size (buf_ptr, true_basereg, true_basereg, 4);
- insert_len = buf_ptr - buf;
-
- /* Move the old instruction forward to make */
- /* room for 'mov' stored in 'buf_ptr' */
- memmove (old_instruction_start + insert_len, old_instruction_start, (size_t)(*code - old_instruction_start));
- *code += insert_len;
- memcpy (old_instruction_start, buf, insert_len);
-
- /* Sandboxed replacement for the normal membase_emit */
- x86_memindex_emit (*code, dreg, AMD64_R15, offset, basereg, 0);
-
- } else {
- /* Normal default behavior, emit membase memory location */
- x86_membase_emit_body (*code, dreg, basereg, offset);
- }
-}
-
-
-static inline unsigned char*
-amd64_skip_nops (unsigned char* code)
-{
- guint8 in_nop;
- do {
- in_nop = 0;
- if ( code[0] == 0x90) {
- in_nop = 1;
- code += 1;
- }
- if ( code[0] == 0x66 && code[1] == 0x90) {
- in_nop = 1;
- code += 2;
- }
- if (code[0] == 0x0f && code[1] == 0x1f
- && code[2] == 0x00) {
- in_nop = 1;
- code += 3;
- }
- if (code[0] == 0x0f && code[1] == 0x1f
- && code[2] == 0x40 && code[3] == 0x00) {
- in_nop = 1;
- code += 4;
- }
- if (code[0] == 0x0f && code[1] == 0x1f
- && code[2] == 0x44 && code[3] == 0x00
- && code[4] == 0x00) {
- in_nop = 1;
- code += 5;
- }
- if (code[0] == 0x66 && code[1] == 0x0f
- && code[2] == 0x1f && code[3] == 0x44
- && code[4] == 0x00 && code[5] == 0x00) {
- in_nop = 1;
- code += 6;
- }
- if (code[0] == 0x0f && code[1] == 0x1f
- && code[2] == 0x80 && code[3] == 0x00
- && code[4] == 0x00 && code[5] == 0x00
- && code[6] == 0x00) {
- in_nop = 1;
- code += 7;
- }
- if (code[0] == 0x0f && code[1] == 0x1f
- && code[2] == 0x84 && code[3] == 0x00
- && code[4] == 0x00 && code[5] == 0x00
- && code[6] == 0x00 && code[7] == 0x00) {
- in_nop = 1;
- code += 8;
- }
- } while ( in_nop );
- return code;
-}
-
-guint8*
-mono_arch_nacl_skip_nops (guint8* code)
-{
- return amd64_skip_nops(code);
-}
-
-#endif /*__native_client_codegen__*/
-