Skip to content
adava edited this page Feb 20, 2019 · 8 revisions

In this section, we explain how data for translation and interpretation flow in QEMU. In the translation process, the dissassember reads the guest code and need to store the instruction opcodes and the operands for the opcodes for later processing. The opcodes will be stored in an architecture independent manner. An example of an opcode that would be stored is INDEX_op_mov_i32. Opcodes for a block will be stored in an array. We elaborate more on this in Opcodes container subsection. The operands for an opcode will be stored in a subtle manner. For interpretation, more information in addition to the value of an operand is required e.g. whether the operand is a register type, memory or constant. Henceforth, an operand would be wrapped in the TCGTemp data structure. We talk more about this data structure in TCGTemp subsection. An offset to a TCGTemp object containing the operand for an operation will be stored in the operand container. We discuss Operands container in the corresponding subsection. Later in the interpretation process, we read the opcodes one by one from the Opcodes container and their operands from the Operands container. Interpreting the opcodes is not very complicated; we only need to know what the corresponding opcode for the host architecture is. The operands, however, need further processing. For memories and the constants we shall pass the address offset and the value. However, for every instruction, a register [or a set of registers] shall be used. This register allocation needs extra effort. For instance, we need to remember that for the former instruction we used the register EAX and for the current instruction we should use another instruction. We elaborate more on this in Registers allocation.

TCG data structures

In this subsection, we talk about the central data structures that are used in the data flow of the QEMU. We especially focus on the guest memory although there are many other important data structures used by Qemu for the translation and interpretation.

Guest memory

All memory that will be referenced while executing guest code on the host is allocated from the guest memory data structure that is TCGContext. Allocation from this pool is through using TCGTemp data structure. In following subsections, we talk about these two data structures.

TCGContext

The structure of this data structure and the memory layout for TCGContext is shown below. TCGContext saves the guest variables in TCGTemp objects. Guest variables include local, global and register variables. The first two are stored in the lower offsets and the local variables are stored in the higher offsets of the temps array. Initialization of the global variables including the registers happen in cpu_x86_init. Precisely, registers are allocated from the global pool in optimize_flags_init. We further elaborate on this in Registers allocation. Global variables of a program are initialized in the tcg_context_init function before we start the translation. Henceforth, nb_globals in this function will be finalized. For local variables, QEMU allocates TCGTemp objects after the global variables per function. This means QEMU needs to set nb_temps to the nb_globals plus 1. For each translation nb_temps is initialized to nb_globals in cpu_gen_code, tcg_func_start.

Figure 9. Guest memory simulated by TCGContext

struct TCGContext { uint8_t *pool_cur, *pool_end; TCGPool *pool_first, *pool_current; TCGLabel *labels; int nb_labels; TCGTemp temps; / globals first, temps after / //sina: the name is misleading; the temps store the globals and the registers. Could be that for shadow memory we use larger indexes. int nb_globals; int nb_temps; / index of free temps, -1 if none */ int first_free_temp[TCG_TYPE_COUNT * 2];

	    /* goto_tb support */
	    uint8_t *code_buf;
	    unsigned long *tb_next;
	    uint16_t *tb_next_offset;
	    uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */

	    /* liveness analysis */
	    uint16_t *op_dead_args; /* for each operation, each bit tells if the
			               corresponding argument is dead */
	    
	    /* tells in which temporary a given register is. It does not take
	       into account fixed registers */
	    int reg_to_temp[TCG_TARGET_NB_REGS];
	    TCGRegSet reserved_regs;
	    tcg_target_long current_frame_offset;
	    tcg_target_long frame_start;
	    tcg_target_long frame_end;
	    int frame_reg;

	    uint8_t *code_ptr;
	    TCGTemp static_temps[TCG_MAX_TEMPS];

	    TCGHelperInfo *helpers;
	    int nb_helpers;
	    int allocated_helpers;
	    int helpers_sorted;

	#ifdef CONFIG_PROFILER
	    /* profiling info */
	    int64_t tb_count1;
	    int64_t tb_count;
	    int64_t op_count; /* total insn count */
	    int op_count_max; /* max insn per TB */
	    int64_t temp_count;
	    int temp_count_max;
	    int64_t del_op_count;
	    int64_t code_in_len;
	    int64_t code_out_len;
	    int64_t interm_time;
	    int64_t code_time;
	    int64_t la_time;
	    int64_t restore_count;
	    int64_t restore_time;
	#endif

	#ifdef CONFIG_DEBUG_TCG
	    int temps_in_use;
	#endif
	};