<commit_before>/* 
 * compiler.c
 * by WN @ Mar. 16, 2010
 */

#include <config.h>
#include <common/defs.h>
#include <common/debug.h>
#include <common/assert.h>
#include <interp/mm.h>
#include <interp/dict.h>
#include <interp/code_cache.h>
#include <xasm/compiler.h>
#include <xasm/tls.h>
#include <xasm/debug.h>
#include <xasm/string.h>

#define MAX_PATCH_SIZE	(256)

/* return value is the position of the value */
static __AI uint32_t *
reset_movl_imm(uint8_t * inst, uint32_t data)
{
	uint32_t * val_addr;
	if ((inst[0] == 0x64) && (inst[1] == 0xc7) && (inst[2] == 0x05)) {
		/* this is movl $0xffffffff, %fs:0x12345678 */
		val_addr = ((uint32_t*)(inst + 7));
	} else if ((inst[0] == 0xc7) && (inst[1] == 0x05)) {
		/* this is movl $0xffffffff, 0x12345678 */
		val_addr = ((uint32_t*)(inst + 6));
	} else {
		assert(0);
	}
	*val_addr = data;
	return val_addr;
}

static __AI uint32_t *
reset_push_imm(uint8_t * inst, uint32_t data)
{
	uint32_t * val_addr;
	if (inst[0] == 0x68) {
		val_addr = (uint32_t*)(&inst[1]);
	} else {
		assert(0);
	}
	*val_addr = data;
	return val_addr;
}

#define template_sym(s)		extern ATTR_HIDDEN uint8_t s[]

template_sym(__set_current_block_template_start);
template_sym(__set_current_block_template_end);
template_sym(__log_phase_template_start);
template_sym(__log_phase_template_end);
template_sym(__log_phase_template_commit);
template_sym(__log_phase_template_save_ebx);
template_sym(__log_phase_template_save_return_addr);
template_sym(__real_branch_phase_template_start);
template_sym(__real_branch_phase_template_end);


#define ptr_length(a, b)	((uintptr_t)(a) - (uintptr_t)(b))
#define template_offset(t, x)	ptr_length(t##_##x, t##_start)
#define template_sz(x)	template_offset(x, end)
#define inst_in_template(target, t, x)	(((uint8_t*)(target)) + template_offset(t, x))

#define MAX_PATCH_SIZE	(256)
/* see recompile_ud , an unconditional branch should
 * have at least 6 bytes */
#define SMALLEST_PATCH_SIZE	(6)

/* return value is the address of the value in the critical movl */
static __AI uint32_t *
copy_log_phase(uint8_t * target)
{
	memcpy(target, __log_phase_template_start,
			template_sz(__log_phase_template));
	uint8_t * movl_inst = inst_in_template(target,
			__log_phase_template, save_return_addr);
	return reset_movl_imm(movl_inst, (uint32_t)(uintptr_t)inst_in_template(target,
				__log_phase_template, end));
}

static int
compile_branch(uint8_t * patch_code, uint8_t * branch,
		enum exit_type * pexit_type, uint32_t ** log_phase_retaddr_fix,
		int * recompile_branch_offset)
{
#warning unfinished
	TRACE(COMPILER, "compiling branch %p\n", branch);
	*log_phase_retaddr_fix = NULL;
	*recompile_branch_offset = 0;
	uint8_t inst1 = branch[0];
	uint8_t inst2 = branch[1];
	uint8_t inst3 = branch[2];
	const int real_branch_template_sz =
		template_sz(__real_branch_phase_template);
	const int log_phase_template_sz =
		template_sz(__log_phase_template);
	switch (inst1) {
#define COMP_Jxx(jxx, untaken_exit, taken_exit) do {	\
	extern uint8_t __##jxx##_template_start[] ATTR_HIDDEN; 		\
	extern uint8_t __##jxx##_template_end[] ATTR_HIDDEN; 		\
	extern uint8_t __##jxx##_template_taken_movl[] ATTR_HIDDEN; \
	extern uint8_t __##jxx##_template_untaken_movl[] ATTR_HIDDEN; \
	*pexit_type = EXIT_COND_DIRECT;								\
	void * ___untaken_exit = untaken_exit;							\
	void * ___taken_exit = taken_exit;								\
	int ___patch_sz = template_sz(__##jxx##_template) + 				\
					log_phase_template_sz +			\
					real_branch_template_sz;	\
	assert(___patch_sz <= MAX_PATCH_SIZE);							\
	memcpy(patch_code, (void*)__##jxx##_template_start, template_sz(__##jxx##_template));\
	reset_movl_imm(inst_in_template(patch_code, __##jxx##_template, taken_movl), \
			(uint32_t)(___taken_exit)); \
	reset_movl_imm(inst_in_template(patch_code, __##jxx##_template, untaken_movl), \
			(uint32_t)(___untaken_exit)); \
	*log_phase_retaddr_fix = copy_log_phase(patch_code + template_sz(__##jxx##_template));\
	memcpy(patch_code + \
			template_sz(__##jxx##_template) + \
			log_phase_template_sz,	\
			__real_branch_phase_template_start, \
			real_branch_template_sz);	\
	return ___patch_sz;\
} while(0)

#define COMP_Jxx_8b(jxx) COMP_Jxx(jxx, branch + 2, branch + 2 + *((int8_t*)(branch + 1)))
#define CASE_Jxx_8b(num, jxx)	case (num): {COMP_Jxx_8b(jxx); break;}

		CASE_Jxx_8b(0x70, jo)
		CASE_Jxx_8b(0x71, jno)
		CASE_Jxx_8b(0x72, jb)
		CASE_Jxx_8b(0x73, jnb)
		CASE_Jxx_8b(0x74, jz)
		CASE_Jxx_8b(0x75, jnz)
		CASE_Jxx_8b(0x76, jna)
		CASE_Jxx_8b(0x77, ja)

		CASE_Jxx_8b(0x78, js)
		CASE_Jxx_8b(0x79, jns)
		CASE_Jxx_8b(0x7a, jp)
		CASE_Jxx_8b(0x7b, jnp)
		CASE_Jxx_8b(0x7c, jl)
		CASE_Jxx_8b(0x7d, jge)
		CASE_Jxx_8b(0x7e, jle)
		CASE_Jxx_8b(0x7f, jg)

#undef COMP_Jxx_8b
#undef CASE_Jxx_8b

		case 0xeb: {
			template_sym(__direct_jmp_template_start);
			template_sym(__direct_jmp_template_end);
			/* this is short jmp */
			*pexit_type = EXIT_UNCOND_DIRECT;
			int patch_sz = template_sz(__direct_jmp_template) +
				real_branch_template_sz;
			void * target = branch + 2 + *((int8_t*)(branch + 1));
			memcpy(patch_code, __direct_jmp_template_start,
					template_sz(__direct_jmp_template));
			reset_movl_imm(patch_code, (uint32_t)(target));
			/* no log phase */
			memcpy(patch_code + template_sz(__direct_jmp_template),
					__real_branch_phase_template_start,
					real_branch_template_sz);
			*recompile_branch_offset = 0;
			return patch_sz;
		}
<commit_msg>add 32bit jmp; test_link segfault<commit_after>/* 
 * compiler.c
 * by WN @ Mar. 16, 2010
 */

#include <config.h>
#include <common/defs.h>
#include <common/debug.h>
#include <common/assert.h>
#include <interp/mm.h>
#include <interp/dict.h>
#include <interp/code_cache.h>
#include <xasm/compiler.h>
#include <xasm/tls.h>
#include <xasm/debug.h>
#include <xasm/string.h>

#define MAX_PATCH_SIZE	(256)

/* return value is the position of the value */
static __AI uint32_t *
reset_movl_imm(uint8_t * inst, uint32_t data)
{
	uint32_t * val_addr;
	if ((inst[0] == 0x64) && (inst[1] == 0xc7) && (inst[2] == 0x05)) {
		/* this is movl $0xffffffff, %fs:0x12345678 */
		val_addr = ((uint32_t*)(inst + 7));
	} else if ((inst[0] == 0xc7) && (inst[1] == 0x05)) {
		/* this is movl $0xffffffff, 0x12345678 */
		val_addr = ((uint32_t*)(inst + 6));
	} else {
		assert(0);
	}
	*val_addr = data;
	return val_addr;
}

static __AI uint32_t *
reset_push_imm(uint8_t * inst, uint32_t data)
{
	uint32_t * val_addr;
	if (inst[0] == 0x68) {
		val_addr = (uint32_t*)(&inst[1]);
	} else {
		assert(0);
	}
	*val_addr = data;
	return val_addr;
}

#define template_sym(s)		extern ATTR_HIDDEN uint8_t s[]

template_sym(__set_current_block_template_start);
template_sym(__set_current_block_template_end);
template_sym(__log_phase_template_start);
template_sym(__log_phase_template_end);
template_sym(__log_phase_template_commit);
template_sym(__log_phase_template_save_ebx);
template_sym(__log_phase_template_save_return_addr);
template_sym(__real_branch_phase_template_start);
template_sym(__real_branch_phase_template_end);


#define ptr_length(a, b)	((uintptr_t)(a) - (uintptr_t)(b))
#define template_offset(t, x)	ptr_length(t##_##x, t##_start)
#define template_sz(x)	template_offset(x, end)
#define inst_in_template(target, t, x)	(((uint8_t*)(target)) + template_offset(t, x))

#define MAX_PATCH_SIZE	(256)
/* see recompile_ud , an unconditional branch should
 * have at least 6 bytes */
#define SMALLEST_PATCH_SIZE	(6)

/* return value is the address of the value in the critical movl */
static __AI uint32_t *
copy_log_phase(uint8_t * target)
{
	memcpy(target, __log_phase_template_start,
			template_sz(__log_phase_template));
	uint8_t * movl_inst = inst_in_template(target,
			__log_phase_template, save_return_addr);
	return reset_movl_imm(movl_inst, (uint32_t)(uintptr_t)inst_in_template(target,
				__log_phase_template, end));
}

static int
compile_branch(uint8_t * patch_code, uint8_t * branch,
		enum exit_type * pexit_type, uint32_t ** log_phase_retaddr_fix,
		int * recompile_branch_offset)
{
#warning unfinished
	TRACE(COMPILER, "compiling branch %p\n", branch);
	*log_phase_retaddr_fix = NULL;
	*recompile_branch_offset = 0;
	uint8_t inst1 = branch[0];
	uint8_t inst2 = branch[1];
	uint8_t inst3 = branch[2];
	const int real_branch_template_sz =
		template_sz(__real_branch_phase_template);
	const int log_phase_template_sz =
		template_sz(__log_phase_template);
	switch (inst1) {
#define COMP_Jxx(jxx, untaken_exit, taken_exit) do {	\
	extern uint8_t __##jxx##_template_start[] ATTR_HIDDEN; 		\
	extern uint8_t __##jxx##_template_end[] ATTR_HIDDEN; 		\
	extern uint8_t __##jxx##_template_taken_movl[] ATTR_HIDDEN; \
	extern uint8_t __##jxx##_template_untaken_movl[] ATTR_HIDDEN; \
	*pexit_type = EXIT_COND_DIRECT;								\
	void * ___untaken_exit = untaken_exit;							\
	void * ___taken_exit = taken_exit;								\
	int ___patch_sz = template_sz(__##jxx##_template) + 				\
					log_phase_template_sz +			\
					real_branch_template_sz;	\
	assert(___patch_sz <= MAX_PATCH_SIZE);							\
	memcpy(patch_code, (void*)__##jxx##_template_start, template_sz(__##jxx##_template));\
	reset_movl_imm(inst_in_template(patch_code, __##jxx##_template, taken_movl), \
			(uint32_t)(___taken_exit)); \
	reset_movl_imm(inst_in_template(patch_code, __##jxx##_template, untaken_movl), \
			(uint32_t)(___untaken_exit)); \
	*log_phase_retaddr_fix = copy_log_phase(patch_code + template_sz(__##jxx##_template));\
	memcpy(patch_code + \
			template_sz(__##jxx##_template) + \
			log_phase_template_sz,	\
			__real_branch_phase_template_start, \
			real_branch_template_sz);	\
	return ___patch_sz;\
} while(0)

#define COMP_Jxx_8b(jxx) COMP_Jxx(jxx, branch + 2, branch + 2 + *((int8_t*)(branch + 1)))
#define CASE_Jxx_8b(num, jxx)	case (num): {COMP_Jxx_8b(jxx); break;}

		CASE_Jxx_8b(0x70, jo)
		CASE_Jxx_8b(0x71, jno)
		CASE_Jxx_8b(0x72, jb)
		CASE_Jxx_8b(0x73, jnb)
		CASE_Jxx_8b(0x74, jz)
		CASE_Jxx_8b(0x75, jnz)
		CASE_Jxx_8b(0x76, jna)
		CASE_Jxx_8b(0x77, ja)

		CASE_Jxx_8b(0x78, js)
		CASE_Jxx_8b(0x79, jns)
		CASE_Jxx_8b(0x7a, jp)
		CASE_Jxx_8b(0x7b, jnp)
		CASE_Jxx_8b(0x7c, jl)
		CASE_Jxx_8b(0x7d, jge)
		CASE_Jxx_8b(0x7e, jle)
		CASE_Jxx_8b(0x7f, jg)

#undef COMP_Jxx_8b
#undef CASE_Jxx_8b

		case 0xe9:
		case 0xeb: {
			template_sym(__direct_jmp_template_start);
			template_sym(__direct_jmp_template_end);
			/* 0xeb is short jmp, 0xe9 is long jmp */
			*pexit_type = EXIT_UNCOND_DIRECT;
			int patch_sz = template_sz(__direct_jmp_template) +
				real_branch_template_sz;
			void * target;
			if (inst1 == 0xeb)
				target = branch + 2 + *((int8_t*)(branch + 1));
			else
				target = branch + 5 + *((int32_t*)(branch + 1));
			memcpy(patch_code, __direct_jmp_template_start,
					template_sz(__direct_jmp_template));
			reset_movl_imm(patch_code, (uint32_t)(target));
			/* no log phase */
			memcpy(patch_code + template_sz(__direct_jmp_template),
					__real_branch_phase_template_start,
					real_branch_template_sz);
			*recompile_branch_offset = 0;
			return patch_sz;
		}

{'fraction_non_alphanumeric': 0.12923497267759562, 'fraction_numerical': 0.03524590163934426, 'mean_word_length': 5.528537455410226, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 4, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4867773', 'n_tokens_mistral': 5063, 'n_tokens_neox': 4613, 'n_words': 772}