145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*
245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * x86 bytecode utility functions
345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *  Copyright (C) 2001-2007  Peter Johnson
545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Redistribution and use in source and binary forms, with or without
745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * modification, are permitted provided that the following conditions
845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * are met:
945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 1. Redistributions of source code must retain the above copyright
1045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer.
1145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
1245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer in the
1345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    documentation and/or other materials provided with the distribution.
1445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
1545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
1645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
1945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * POSSIBILITY OF SUCH DAMAGE.
2645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
2745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include <util.h>
2845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
2945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include <libyasm.h>
3045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "x86arch.h"
3245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Bytecode callback function prototypes */
3545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
3645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void x86_bc_insn_destroy(void *contents);
3745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void x86_bc_insn_print(const void *contents, FILE *f,
3845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                              int indent_level);
3945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_insn_calc_len(yasm_bytecode *bc,
4045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                yasm_bc_add_span_func add_span,
4145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                void *add_span_data);
4245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val,
4345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                              long new_val, /*@out@*/ long *neg_thres,
4445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                              /*@out@*/ long *pos_thres);
4545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
46d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                               unsigned char *bufstart,
4745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                               void *d, yasm_output_value_func output_value,
4845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                               /*@null@*/ yasm_output_reloc_func output_reloc);
4945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void x86_bc_jmp_destroy(void *contents);
5145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void x86_bc_jmp_print(const void *contents, FILE *f, int indent_level);
5245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_jmp_calc_len(yasm_bytecode *bc,
5345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                               yasm_bc_add_span_func add_span,
5445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                               void *add_span_data);
5545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val,
5645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                             long new_val, /*@out@*/ long *neg_thres,
5745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                             /*@out@*/ long *pos_thres);
5845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
59d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                              unsigned char *bufstart,
6045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                              void *d, yasm_output_value_func output_value,
6145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                              /*@null@*/ yasm_output_reloc_func output_reloc);
6245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void x86_bc_jmpfar_destroy(void *contents);
6445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void x86_bc_jmpfar_print(const void *contents, FILE *f,
6545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                int indent_level);
6645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_jmpfar_calc_len(yasm_bytecode *bc,
6745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                  yasm_bc_add_span_func add_span,
6845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                  void *add_span_data);
6945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int x86_bc_jmpfar_tobytes
70d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    (yasm_bytecode *bc, unsigned char **bufp, unsigned char *bufstart, void *d,
7145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     yasm_output_value_func output_value,
7245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     /*@null@*/ yasm_output_reloc_func output_reloc);
7345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
7445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/* Bytecode callback structures */
7545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
7645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic const yasm_bytecode_callback x86_bc_callback_insn = {
7745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_insn_destroy,
7845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_insn_print,
7945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bc_finalize_common,
8045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    NULL,
8145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_insn_calc_len,
8245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_insn_expand,
8345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_insn_tobytes,
8445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    0
8545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org};
8645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic const yasm_bytecode_callback x86_bc_callback_jmp = {
8845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmp_destroy,
8945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmp_print,
9045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bc_finalize_common,
9145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    NULL,
9245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmp_calc_len,
9345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmp_expand,
9445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmp_tobytes,
9545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    0
9645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org};
9745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
9845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic const yasm_bytecode_callback x86_bc_callback_jmpfar = {
9945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmpfar_destroy,
10045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmpfar_print,
10145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bc_finalize_common,
10245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    NULL,
10345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmpfar_calc_len,
10445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bc_expand_common,
10545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_bc_jmpfar_tobytes,
10645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    0
10745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org};
10845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
10945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
110a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.orgyasm_x86__set_rex_from_reg(unsigned char *rex, unsigned char *low3,
111a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                           uintptr_t reg, unsigned int bits,
112a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                           x86_rex_bit_pos rexbit)
11345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
11445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *low3 = (unsigned char)(reg&7);
11545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
11645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (bits == 64) {
11745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        x86_expritem_reg_size size = (x86_expritem_reg_size)(reg & ~0xFUL);
11845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
11945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (size == X86_REG8X || (reg & 0xF) >= 8) {
120a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            /* Check to make sure we can set it */
121a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            if (*rex == 0xff) {
122a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                yasm_error_set(YASM_ERROR_TYPE,
123a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    N_("cannot use A/B/C/DH with instruction needing REX"));
124a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                return 1;
12545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
126a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            *rex |= 0x40 | (((reg & 8) >> 3) << rexbit);
12745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else if (size == X86_REG8 && (reg & 7) >= 4) {
12845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* AH/BH/CH/DH, so no REX allowed */
12945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (*rex != 0 && *rex != 0xff) {
13045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_error_set(YASM_ERROR_TYPE,
13145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    N_("cannot use A/B/C/DH with instruction needing REX"));
13245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
13345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
13445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            *rex = 0xff;    /* Flag so we can NEVER set it (see above) */
13545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
13645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
13745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
13845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
13945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
14045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
14245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__bc_transform_insn(yasm_bytecode *bc, x86_insn *insn)
14345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
14445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bc_transform(bc, &x86_bc_callback_insn, insn);
14545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
14645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
14745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
14845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__bc_transform_jmp(yasm_bytecode *bc, x86_jmp *jmp)
14945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
15045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bc_transform(bc, &x86_bc_callback_jmp, jmp);
15145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
15245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
15345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
15445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__bc_transform_jmpfar(yasm_bytecode *bc, x86_jmpfar *jmpfar)
15545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
15645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bc_transform(bc, &x86_bc_callback_jmpfar, jmpfar);
15745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
15845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
15945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
160a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.orgyasm_x86__ea_init(x86_effaddr *x86_ea, unsigned int spare,
161a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                  yasm_bytecode *precbc)
16245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
16345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (yasm_value_finalize(&x86_ea->ea.disp, precbc))
16445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_error_set(YASM_ERROR_TOO_COMPLEX,
16545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                       N_("effective address too complex"));
16645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->modrm &= 0xC7;                  /* zero spare/reg bits */
16745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->modrm |= (spare << 3) & 0x38;   /* plug in provided bits */
16845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
16945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
17045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
17145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__ea_set_disponly(x86_effaddr *x86_ea)
17245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
17345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->valid_modrm = 0;
17445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->need_modrm = 0;
17545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->valid_sib = 0;
17645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->need_sib = 0;
17745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
17845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
17945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic x86_effaddr *
18045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgea_create(void)
18145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
18245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_effaddr *x86_ea = yasm_xmalloc(sizeof(x86_effaddr));
18345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
18445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_initialize(&x86_ea->ea.disp, NULL, 0);
18545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.need_nonzero_len = 0;
18645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.need_disp = 0;
18745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.nosplit = 0;
18845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.strong = 0;
18945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.segreg = 0;
19045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.pc_rel = 0;
19145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.not_pc_rel = 0;
19245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.data_len = 0;
193d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    x86_ea->vsib_mode = 0;
19445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->modrm = 0;
19545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->valid_modrm = 0;
19645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->need_modrm = 0;
19745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->sib = 0;
19845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->valid_sib = 0;
19945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->need_sib = 0;
20045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
20145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return x86_ea;
20245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
20345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
20445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_effaddr *
20545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__ea_create_reg(x86_effaddr *x86_ea, unsigned long reg,
206a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                        unsigned char *rex, unsigned int bits)
20745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
20845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char rm;
20945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
210a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    if (yasm_x86__set_rex_from_reg(rex, &rm, reg, bits, X86_REX_B))
21145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return NULL;
21245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
21345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!x86_ea)
21445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        x86_ea = ea_create();
21545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->modrm = 0xC0 | rm;  /* Mod=11, R/M=Reg, Reg=0 */
21645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->valid_modrm = 1;
21745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->need_modrm = 1;
21845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
21945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return x86_ea;
22045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
22145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
22245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_effaddr *
22345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__ea_create_expr(yasm_arch *arch, yasm_expr *e)
22445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
22545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch;
22645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_effaddr *x86_ea;
22745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
22845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea = ea_create();
22945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
23045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (arch_x86->parser == X86_PARSER_GAS) {
231a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        /* Need to change foo+rip into foo wrt rip (even in .intel_syntax mode).
23245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * Note this assumes a particular ordering coming from the parser
23345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * to work (it's not very smart)!
23445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
23545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (e->op == YASM_EXPR_ADD && e->terms[0].type == YASM_EXPR_REG
23645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            && e->terms[0].data.reg == X86_RIP) {
23745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* replace register with 0 */
23845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[0].type = YASM_EXPR_INT;
23945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e->terms[0].data.intn = yasm_intnum_create_uint(0);
24045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* build new wrt expression */
24145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            e = yasm_expr_create(YASM_EXPR_WRT, yasm_expr_expr(e),
24245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                 yasm_expr_reg(X86_RIP), e->line);
24345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
24445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
24545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_initialize(&x86_ea->ea.disp, e, 0);
24645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.need_disp = 1;
24745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->need_modrm = 1;
24845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* We won't know whether we need an SIB until we know more about expr and
24945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * the BITS/address override setting.
25045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
25145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->need_sib = 0xff;
25245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
25345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.data_len = 0;
25445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
25545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return (yasm_effaddr *)x86_ea;
25645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
25745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
25845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@-compmempass@*/
25945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_effaddr *
26045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__ea_create_imm(x86_effaddr *x86_ea, yasm_expr *imm,
26145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        unsigned int im_len)
26245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
26345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!x86_ea)
26445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        x86_ea = ea_create();
26545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_initialize(&x86_ea->ea.disp, imm, im_len);
26645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_ea->ea.need_disp = 1;
26745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
26845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return x86_ea;
26945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
27045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*@=compmempass@*/
27145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
27245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
27345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__bc_apply_prefixes(x86_common *common, unsigned char *rex,
27445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            unsigned int def_opersize_64,
27545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            unsigned int num_prefixes, uintptr_t *prefixes)
27645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
27745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int i;
27845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int first = 1;
27945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
28045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<num_prefixes; i++) {
28145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        switch ((x86_parse_insn_prefix)(prefixes[i] & 0xff00)) {
28245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case X86_LOCKREP:
28345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (common->lockrep_pre != 0)
28445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_warn_set(YASM_WARN_GENERAL,
28545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        N_("multiple LOCK or REP prefixes, using leftmost"));
28645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                common->lockrep_pre = (unsigned char)prefixes[i] & 0xff;
28745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
28845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case X86_ADDRSIZE:
28945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                common->addrsize = (unsigned char)prefixes[i] & 0xff;
29045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
29145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case X86_OPERSIZE:
29245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                common->opersize = (unsigned char)prefixes[i] & 0xff;
29345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (common->mode_bits == 64 && common->opersize == 64 &&
29445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    def_opersize_64 != 64) {
29545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (!rex)
29645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_warn_set(YASM_WARN_GENERAL,
29745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                      N_("ignoring REX prefix on jump"));
29845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    else if (*rex == 0xff)
29945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_warn_set(YASM_WARN_GENERAL,
30045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            N_("REX prefix not allowed on this instruction, ignoring"));
30145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    else
30245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        *rex = 0x48;
30345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
30445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
30545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case X86_SEGREG:
30645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* This is a hack.. we should really be putting this in the
30745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * the effective address!
30845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 */
30945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                common->lockrep_pre = (unsigned char)prefixes[i] & 0xff;
31045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
31145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            case X86_REX:
31245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (!rex)
31345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_warn_set(YASM_WARN_GENERAL,
31445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                  N_("ignoring REX prefix on jump"));
31545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                else if (*rex == 0xff)
31645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_warn_set(YASM_WARN_GENERAL,
31745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        N_("REX prefix not allowed on this instruction, ignoring"));
31845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                else {
31945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (*rex != 0) {
32045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if (first)
32145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            yasm_warn_set(YASM_WARN_GENERAL,
32245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                N_("overriding generated REX prefix"));
32345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        else
32445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            yasm_warn_set(YASM_WARN_GENERAL,
32545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                N_("multiple REX prefixes, using leftmost"));
32645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    }
32745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* Here we assume that we can't get this prefix in non
32845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     * 64 bit mode due to checks in parse_check_prefix().
32945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     */
33045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    common->mode_bits = 64;
33145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    *rex = (unsigned char)prefixes[i] & 0xff;
33245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
33345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                first = 0;
33445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
33545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
33645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
33745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
33845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
33945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
34045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_insn_destroy(void *contents)
34145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
34245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_insn *insn = (x86_insn *)contents;
34345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (insn->x86_ea)
34445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_x86__ea_destroy((yasm_effaddr *)insn->x86_ea);
34545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (insn->imm) {
34645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_value_delete(insn->imm);
34745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_xfree(insn->imm);
34845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
34945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_xfree(contents);
35045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
35145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
35245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
35345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_jmp_destroy(void *contents)
35445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
35545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_jmp *jmp = (x86_jmp *)contents;
35645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_delete(&jmp->target);
35745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_xfree(contents);
35845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
35945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
36045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
36145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_jmpfar_destroy(void *contents)
36245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
36345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_jmpfar *jmpfar = (x86_jmpfar *)contents;
36445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_delete(&jmpfar->segment);
36545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_delete(&jmpfar->offset);
36645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_xfree(contents);
36745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
36845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
36945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
37045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__ea_destroy(yasm_effaddr *ea)
37145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
37245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_delete(&ea->disp);
37345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_xfree(ea);
37445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
37545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
37645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
37745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__ea_print(const yasm_effaddr *ea, FILE *f, int indent_level)
37845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
37945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const x86_effaddr *x86_ea = (const x86_effaddr *)ea;
38045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sDisp:\n", indent_level, "");
38145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_print(&ea->disp, f, indent_level+1);
38245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sNoSplit=%u\n", indent_level, "", (unsigned int)ea->nosplit);
38345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sSegmentOv=%02x\n", indent_level, "",
38445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)x86_ea->ea.segreg);
385d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    fprintf(f, "%*sVSIBMode=%u\n", indent_level, "",
386d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org            (unsigned int)x86_ea->vsib_mode);
38745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sModRM=%03o ValidRM=%u NeedRM=%u\n", indent_level, "",
38845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)x86_ea->modrm, (unsigned int)x86_ea->valid_modrm,
38945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)x86_ea->need_modrm);
39045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sSIB=%03o ValidSIB=%u NeedSIB=%u\n", indent_level, "",
39145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)x86_ea->sib, (unsigned int)x86_ea->valid_sib,
39245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)x86_ea->need_sib);
39345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
39445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
39545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
39645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_common_print(const x86_common *common, FILE *f, int indent_level)
39745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
39845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sAddrSize=%u OperSize=%u LockRepPre=%02x BITS=%u\n",
39945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            indent_level, "",
40045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)common->addrsize,
40145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)common->opersize,
40245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)common->lockrep_pre,
40345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)common->mode_bits);
40445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
40545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
40645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
40745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_opcode_print(const x86_opcode *opcode, FILE *f, int indent_level)
40845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
40945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sOpcode: %02x %02x %02x OpLen=%u\n", indent_level, "",
41045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)opcode->opcode[0],
41145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)opcode->opcode[1],
41245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)opcode->opcode[2],
41345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)opcode->len);
41445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
41545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
41645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
41745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_insn_print(const void *contents, FILE *f, int indent_level)
41845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
41945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const x86_insn *insn = (const x86_insn *)contents;
42045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
42145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*s_Instruction_\n", indent_level, "");
42245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sEffective Address:", indent_level, "");
42345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (insn->x86_ea) {
42445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, "\n");
42545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_x86__ea_print((yasm_effaddr *)insn->x86_ea, f, indent_level+1);
42645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    } else
42745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, " (nil)\n");
42845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sImmediate Value:", indent_level, "");
42945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!insn->imm)
43045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, " (nil)\n");
43145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else {
43245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        indent_level++;
43345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, "\n");
43445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_value_print(insn->imm, f, indent_level);
43545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        indent_level--;
43645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
43745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_opcode_print(&insn->opcode, f, indent_level);
43845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_common_print(&insn->common, f, indent_level);
43945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sSpPre=%02x REX=%03o PostOp=%u\n", indent_level, "",
44045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)insn->special_prefix,
44145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)insn->rex,
44245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (unsigned int)insn->postop);
44345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
44445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
44545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
44645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_jmp_print(const void *contents, FILE *f, int indent_level)
44745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
44845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const x86_jmp *jmp = (const x86_jmp *)contents;
44945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
45045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*s_Jump_\n", indent_level, "");
45145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sTarget:\n", indent_level, "");
45245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_print(&jmp->target, f, indent_level+1);
45345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* FIXME
45445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sOrigin=\n", indent_level, "");
45545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_symrec_print(jmp->origin, f, indent_level+1);
45645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    */
45745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "\n%*sShort Form:\n", indent_level, "");
45845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->shortop.len == 0)
45945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, "%*sNone\n", indent_level+1, "");
46045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else
46145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        x86_opcode_print(&jmp->shortop, f, indent_level+1);
46245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sNear Form:\n", indent_level, "");
46345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->nearop.len == 0)
46445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        fprintf(f, "%*sNone\n", indent_level+1, "");
46545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else
46645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        x86_opcode_print(&jmp->nearop, f, indent_level+1);
46745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sOpSel=", indent_level, "");
46845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (jmp->op_sel) {
46945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_NONE:
47045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "None");
47145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
47245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_SHORT:
47345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "Short");
47445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
47545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_NEAR:
47645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "Near");
47745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
47845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_SHORT_FORCED:
47945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "Forced Short");
48045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
48145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_NEAR_FORCED:
48245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "Forced Near");
48345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
48445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
48545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            fprintf(f, "UNKNOWN!!");
48645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
48745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
48845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_common_print(&jmp->common, f, indent_level);
48945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
49045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
49145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
49245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_jmpfar_print(const void *contents, FILE *f, int indent_level)
49345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
49445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const x86_jmpfar *jmpfar = (const x86_jmpfar *)contents;
49545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
49645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*s_Far_Jump_\n", indent_level, "");
49745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sSegment:\n", indent_level, "");
49845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_print(&jmpfar->segment, f, indent_level+1);
49945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    fprintf(f, "%*sOffset:\n", indent_level, "");
50045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value_print(&jmpfar->offset, f, indent_level+1);
50145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_opcode_print(&jmpfar->opcode, f, indent_level);
50245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_common_print(&jmpfar->common, f, indent_level);
50345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
50445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
50545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic unsigned int
50645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_common_calc_len(const x86_common *common)
50745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
50845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int len = 0;
50945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
51045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (common->addrsize != 0 && common->addrsize != common->mode_bits)
51145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        len++;
51245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (common->opersize != 0 &&
51345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ((common->mode_bits != 64 && common->opersize != common->mode_bits) ||
51445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         (common->mode_bits == 64 && common->opersize == 16)))
51545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        len++;
51645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (common->lockrep_pre != 0)
51745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        len++;
51845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
51945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return len;
52045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
52145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
52245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
52345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_insn_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
52445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     void *add_span_data)
52545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
52645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_insn *insn = (x86_insn *)bc->contents;
52745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_effaddr *x86_ea = insn->x86_ea;
52845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value *imm = insn->imm;
52945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
53045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (x86_ea) {
53145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Check validity of effective address and calc R/M bits of
53245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * Mod/RM byte and SIB byte.  We won't know the Mod field
53345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * of the Mod/RM byte until we know more about the
53445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * displacement.
53545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
53645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (yasm_x86__expr_checkea(x86_ea, &insn->common.addrsize,
53745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                insn->common.mode_bits, insn->postop == X86_POSTOP_ADDRESS16,
53845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                &insn->rex, bc))
53945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* failed, don't bother checking rest of insn */
54045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return -1;
54145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
54245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (x86_ea->ea.disp.size == 0 && x86_ea->ea.need_nonzero_len) {
54345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Handle unknown case, default to byte-sized and set as
54445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * critical expression.
54545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
54645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            x86_ea->ea.disp.size = 8;
54745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            add_span(add_span_data, bc, 1, &x86_ea->ea.disp, -128, 127);
54845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
54945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        bc->len += x86_ea->ea.disp.size/8;
55045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
55145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Handle address16 postop case */
55245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->postop == X86_POSTOP_ADDRESS16)
55345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->common.addrsize = 0;
55445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
55545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Compute length of ea and add to total */
55645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        bc->len += x86_ea->need_modrm + (x86_ea->need_sib ? 1:0);
55745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        bc->len += (x86_ea->ea.segreg != 0) ? 1 : 0;
55845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
55945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
56045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (imm) {
56145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        unsigned int immlen = imm->size;
56245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
56345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* TODO: check imm->len vs. sized len from expr? */
56445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
56545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Handle signext_imm8 postop special-casing */
56645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
56745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /*@null@*/ /*@only@*/ yasm_intnum *num;
56845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            num = yasm_value_get_intnum(imm, NULL, 0);
56945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
57045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (!num) {
57145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Unknown; default to byte form and set as critical
57245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 * expression.
57345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 */
57445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                immlen = 8;
57545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                add_span(add_span_data, bc, 2, imm, -128, 127);
57645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            } else {
57745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (yasm_intnum_in_range(num, -128, 127)) {
57845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* We can use the sign-extended byte form: shorten
57945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     * the immediate length to 1 and make the byte form
58045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     * permanent.
58145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                     */
58245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    imm->size = 8;
58345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    imm->sign = 1;
58445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    immlen = 8;
58545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                } else {
58645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* We can't.  Copy over the word-sized opcode. */
58745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    insn->opcode.opcode[0] =
58845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        insn->opcode.opcode[insn->opcode.len];
58945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    insn->opcode.len = 1;
59045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                }
59145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                insn->postop = X86_POSTOP_NONE;
59245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_intnum_destroy(num);
59345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
59445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
59545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
59645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        bc->len += immlen/8;
59745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
59845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
599a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    /* VEX and XOP prefixes never have REX (it's embedded in the opcode).
600a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org     * For VEX, we can come into this function with the three byte form,
601a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org     * so we need to see if we can optimize to the two byte form.
602a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org     * We can't do it earlier, as we don't know all of the REX byte until now.
60345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
60445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (insn->special_prefix == 0xC4) {
60545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* See if we can shorten the VEX prefix to its two byte form.
60645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * In order to do this, REX.X, REX.B, and REX.W/VEX.W must all be 0,
60745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * and the VEX mmmmm field must be 1.
60845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
60945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if ((insn->opcode.opcode[0] & 0x1F) == 1 &&
61045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (insn->opcode.opcode[1] & 0x80) == 0 &&
61145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            (insn->rex == 0xff || (insn->rex & 0x0B) == 0)) {
61245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.opcode[0] = insn->opcode.opcode[1];
61345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.opcode[1] = insn->opcode.opcode[2];
61445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.opcode[2] = 0; /* sanity */
61545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.len = 2;
61645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->special_prefix = 0xC5;    /* mark as two-byte VEX */
61745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
61845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    } else if (insn->rex != 0xff && insn->rex != 0 &&
619a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org               insn->special_prefix != 0xC5 && insn->special_prefix != 0x8F)
62045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        bc->len++;
62145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
62245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += insn->opcode.len;
62345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += x86_common_calc_len(&insn->common);
62445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += (insn->special_prefix != 0) ? 1:0;
62545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
62645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
62745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
62845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
62945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_insn_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
63045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                   /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
63145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
63245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_insn *insn = (x86_insn *)bc->contents;
63345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_effaddr *x86_ea = insn->x86_ea;
63445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_effaddr *ea = &x86_ea->ea;
63545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value *imm = insn->imm;
63645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
63745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (ea && span == 1) {
63845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Change displacement length into word-sized */
63945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (ea->disp.size == 8) {
64045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            ea->disp.size = (insn->common.addrsize == 16) ? 16 : 32;
64145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            x86_ea->modrm &= ~0300;
64245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            x86_ea->modrm |= 0200;
64345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            bc->len--;
64445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            bc->len += ea->disp.size/8;
64545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
64645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
64745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
64845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (imm && span == 2) {
64945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
65045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Update bc->len for new opcode and immediate size */
65145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            bc->len -= insn->opcode.len;
65245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            bc->len += imm->size/8;
65345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
65445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Change to the word-sized opcode */
65545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.opcode[0] = insn->opcode.opcode[insn->opcode.len];
65645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.len = 1;
65745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->postop = X86_POSTOP_NONE;
65845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
65945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
66045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
66145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
66245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
66345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
66445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
66545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_jmp_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
66645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    void *add_span_data)
66745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
66845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_jmp *jmp = (x86_jmp *)bc->contents;
66945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_bytecode *target_prevbc;
67045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char opersize;
67145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
67245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* As opersize may be 0, figure out its "real" value. */
67345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    opersize = (jmp->common.opersize == 0) ?
67445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        jmp->common.mode_bits : jmp->common.opersize;
67545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
67645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += x86_common_calc_len(&jmp->common);
67745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
67845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->op_sel == JMP_NEAR_FORCED || jmp->shortop.len == 0) {
67945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (jmp->nearop.len == 0) {
68045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_error_set(YASM_ERROR_TYPE, N_("near jump does not exist"));
68145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return -1;
68245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
68345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
68445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Near jump, no spans needed */
68545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (jmp->shortop.len == 0)
68645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            jmp->op_sel = JMP_NEAR;
68745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        bc->len += jmp->nearop.len;
68845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        bc->len += (opersize == 16) ? 2 : 4;
68945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
69045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
69145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
69245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
69345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (jmp->shortop.len == 0) {
69445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_error_set(YASM_ERROR_TYPE, N_("short jump does not exist"));
69545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return -1;
69645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
69745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
69845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* We want to be sure to error if we exceed short length, so
69945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * put it in as a dependent expression (falling through).
70045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
70145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
70245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
70345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->target.rel
70445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        && (!yasm_symrec_get_label(jmp->target.rel, &target_prevbc)
70545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            || target_prevbc->section != bc->section)) {
70645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* External or out of segment, so we can't check distance.
70745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * Allowing short jumps depends on the objfmt supporting
70845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * 8-bit relocs.  While most don't, some might, so allow it here.
70945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * Otherwise default to word-sized.
71045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * The objfmt will error if not supported.
71145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
71245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
71345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (jmp->op_sel == JMP_NONE)
71445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                jmp->op_sel = JMP_SHORT;
71545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            bc->len += jmp->shortop.len + 1;
71645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else {
71745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            jmp->op_sel = JMP_NEAR;
71845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            bc->len += jmp->nearop.len;
71945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            bc->len += (opersize == 16) ? 2 : 4;
72045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
72145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
72245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
72345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
72445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Default to short jump and generate span */
72545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->op_sel == JMP_NONE)
72645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        jmp->op_sel = JMP_SHORT;
72745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += jmp->shortop.len + 1;
72845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    add_span(add_span_data, bc, 1, &jmp->target, -128+(long)bc->len,
72945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             127+(long)bc->len);
73045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
73145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
73245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
73345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
73445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_jmp_expand(yasm_bytecode *bc, int span, long old_val, long new_val,
73545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                  /*@out@*/ long *neg_thres, /*@out@*/ long *pos_thres)
73645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
73745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_jmp *jmp = (x86_jmp *)bc->contents;
73845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char opersize;
73945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
74045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (span != 1)
74145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_internal_error(N_("unrecognized span id"));
74245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
74345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* As opersize may be 0, figure out its "real" value. */
74445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    opersize = (jmp->common.opersize == 0) ?
74545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        jmp->common.mode_bits : jmp->common.opersize;
74645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
74745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->op_sel == JMP_SHORT_FORCED || jmp->nearop.len == 0) {
74845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_error_set(YASM_ERROR_VALUE, N_("short jump out of range"));
74945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return -1;
75045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
75145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
75245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (jmp->op_sel == JMP_NEAR)
75345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_internal_error(N_("trying to expand an already-near jump"));
75445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
75545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Upgrade to a near jump */
75645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    jmp->op_sel = JMP_NEAR;
75745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len -= jmp->shortop.len + 1;
75845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += jmp->nearop.len;
75945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += (opersize == 16) ? 2 : 4;
76045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
76145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
76245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
76345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
76445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
76545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_bc_jmpfar_calc_len(yasm_bytecode *bc, yasm_bc_add_span_func add_span,
76645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                       void *add_span_data)
76745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
76845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
76945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char opersize;
77045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
77145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    opersize = (jmpfar->common.opersize == 0) ?
77245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        jmpfar->common.mode_bits : jmpfar->common.opersize;
77345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
77445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += jmpfar->opcode.len;
77545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += 2;       /* segment */
77645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += (opersize == 16) ? 2 : 4;
77745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    bc->len += x86_common_calc_len(&jmpfar->common);
77845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
77945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
78045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
78145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
78245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
78345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_common_tobytes(const x86_common *common, unsigned char **bufp,
78445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                   unsigned int segreg)
78545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
78645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (segreg != 0)
78745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        YASM_WRITE_8(*bufp, (unsigned char)segreg);
78845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (common->addrsize != 0 && common->addrsize != common->mode_bits)
78945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        YASM_WRITE_8(*bufp, 0x67);
79045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (common->opersize != 0 &&
79145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        ((common->mode_bits != 64 && common->opersize != common->mode_bits) ||
79245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         (common->mode_bits == 64 && common->opersize == 16)))
79345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        YASM_WRITE_8(*bufp, 0x66);
79445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (common->lockrep_pre != 0)
79545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        YASM_WRITE_8(*bufp, common->lockrep_pre);
79645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
79745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
79845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic void
79945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgx86_opcode_tobytes(const x86_opcode *opcode, unsigned char **bufp)
80045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
80145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int i;
80245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0; i<opcode->len; i++)
80345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        YASM_WRITE_8(*bufp, opcode->opcode[i]);
80445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
80545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
80645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
807d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.orgx86_bc_insn_tobytes(yasm_bytecode *bc, unsigned char **bufp,
808d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                    unsigned char *bufstart, void *d,
80945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_output_value_func output_value,
81045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /*@unused@*/ yasm_output_reloc_func output_reloc)
81145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
81245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_insn *insn = (x86_insn *)bc->contents;
81345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@null@*/ x86_effaddr *x86_ea = (x86_effaddr *)insn->x86_ea;
81445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_value *imm = insn->imm;
81545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
81645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Prefixes */
81745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_common_tobytes(&insn->common, bufp,
81845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                       x86_ea ? (unsigned int)(x86_ea->ea.segreg>>8) : 0);
81945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (insn->special_prefix != 0)
82045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        YASM_WRITE_8(*bufp, insn->special_prefix);
821a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    if (insn->special_prefix == 0xC4 || insn->special_prefix == 0x8F) {
822a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        /* 3-byte VEX/XOP; merge in 1s complement of REX.R, REX.X, REX.B */
82345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        insn->opcode.opcode[0] &= 0x1F;
82445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->rex != 0xff)
82545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.opcode[0] |= ((~insn->rex) & 0x07) << 5;
82645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* merge REX.W via ORing; there should never be a case in which REX.W
82745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         * is important when VEX.W is already set by the instruction.
82845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org         */
82945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->rex != 0xff && (insn->rex & 0x8) != 0)
83045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.opcode[1] |= 0x80;
83145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    } else if (insn->special_prefix == 0xC5) {
83245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* 2-byte VEX; merge in 1s complement of REX.R */
83345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        insn->opcode.opcode[0] &= 0x7F;
83445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->rex != 0xff && (insn->rex & 0x4) == 0)
83545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            insn->opcode.opcode[0] |= 0x80;
83645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* No other REX bits should be set */
83745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->rex != 0xff && (insn->rex & 0xB) != 0)
83845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_internal_error(N_("x86: REX.WXB set, but 2-byte VEX"));
83945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    } else if (insn->rex != 0xff && insn->rex != 0) {
84045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->common.mode_bits != 64)
84145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_internal_error(N_("x86: got a REX prefix in non-64-bit mode"));
84245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        YASM_WRITE_8(*bufp, insn->rex);
84345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
84445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
84545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Opcode */
84645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_opcode_tobytes(&insn->opcode, bufp);
84745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
84845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Effective address: ModR/M (if required), SIB (if required), and
84945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * displacement (if required).
85045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
85145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (x86_ea) {
85245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (x86_ea->need_modrm) {
85345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (!x86_ea->valid_modrm)
85445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_internal_error(N_("invalid Mod/RM in x86 tobytes_insn"));
85545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            YASM_WRITE_8(*bufp, x86_ea->modrm);
85645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
85745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
85845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (x86_ea->need_sib) {
85945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (!x86_ea->valid_sib)
86045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_internal_error(N_("invalid SIB in x86 tobytes_insn"));
86145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            YASM_WRITE_8(*bufp, x86_ea->sib);
86245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
86345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
86445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (x86_ea->ea.need_disp) {
86545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            unsigned int disp_len = x86_ea->ea.disp.size/8;
86645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
86745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (x86_ea->ea.disp.ip_rel) {
86845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* Adjust relative displacement to end of bytecode */
86945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /*@only@*/ yasm_intnum *delta;
87045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                delta = yasm_intnum_create_int(-(long)bc->len);
87145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                if (!x86_ea->ea.disp.abs)
87245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    x86_ea->ea.disp.abs =
87345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_expr_create_ident(yasm_expr_int(delta), bc->line);
87445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                else
87545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    x86_ea->ea.disp.abs =
87645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        yasm_expr_create(YASM_EXPR_ADD,
87745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                         yasm_expr_expr(x86_ea->ea.disp.abs),
87845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                         yasm_expr_int(delta), bc->line);
87945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
88045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (output_value(&x86_ea->ea.disp, *bufp, disp_len,
881d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                             (unsigned long)(*bufp-bufstart), bc, 1, d))
88245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
88345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            *bufp += disp_len;
88445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
88545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
88645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
88745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Immediate (if required) */
88845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (imm) {
88945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        unsigned int imm_len;
89045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (insn->postop == X86_POSTOP_SIGNEXT_IMM8) {
89145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* If we got here with this postop still set, we need to force
89245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             * imm size to 8 here.
89345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org             */
89445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            imm->size = 8;
89545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            imm->sign = 1;
89645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            imm_len = 1;
89745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else
89845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            imm_len = imm->size/8;
899d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        if (output_value(imm, *bufp, imm_len, (unsigned long)(*bufp-bufstart),
90045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                         bc, 1, d))
90145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return 1;
90245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *bufp += imm_len;
90345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
90445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
90545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
90645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
90745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
90845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
909d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.orgx86_bc_jmp_tobytes(yasm_bytecode *bc, unsigned char **bufp,
910d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                   unsigned char *bufstart, void *d,
91145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                   yasm_output_value_func output_value,
91245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                   /*@unused@*/ yasm_output_reloc_func output_reloc)
91345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
91445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_jmp *jmp = (x86_jmp *)bc->contents;
91545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char opersize;
91645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int i;
91745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@only@*/ yasm_intnum *delta;
91845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
91945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Prefixes */
92045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_common_tobytes(&jmp->common, bufp, 0);
92145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
92245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* As opersize may be 0, figure out its "real" value. */
92345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    opersize = (jmp->common.opersize == 0) ?
92445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        jmp->common.mode_bits : jmp->common.opersize;
92545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
92645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Check here again to see if forms are actually legal. */
92745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    switch (jmp->op_sel) {
92845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_SHORT_FORCED:
92945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_SHORT:
93045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* 1 byte relative displacement */
93145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (jmp->shortop.len == 0)
93245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_internal_error(N_("short jump does not exist"));
93345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
93445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Opcode */
93545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            x86_opcode_tobytes(&jmp->shortop, bufp);
93645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
93745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Adjust relative displacement to end of bytecode */
93845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            delta = yasm_intnum_create_int(-(long)bc->len);
93945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (!jmp->target.abs)
94045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta),
94145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                         bc->line);
94245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
94345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                jmp->target.abs =
94445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_expr_create(YASM_EXPR_ADD,
94545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                     yasm_expr_expr(jmp->target.abs),
94645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                     yasm_expr_int(delta), bc->line);
94745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
94845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            jmp->target.size = 8;
94945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            jmp->target.sign = 1;
95045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (output_value(&jmp->target, *bufp, 1,
951d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                             (unsigned long)(*bufp-bufstart), bc, 1, d))
95245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
95345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            *bufp += 1;
95445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
95545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_NEAR_FORCED:
95645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_NEAR:
95745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* 2/4 byte relative displacement (depending on operand size) */
95845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (jmp->nearop.len == 0) {
95945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_error_set(YASM_ERROR_TYPE,
96045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                               N_("near jump does not exist"));
96145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
96245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
96345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
96445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Opcode */
96545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            x86_opcode_tobytes(&jmp->nearop, bufp);
96645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
96745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            i = (opersize == 16) ? 2 : 4;
96845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
96945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* Adjust relative displacement to end of bytecode */
97045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            delta = yasm_intnum_create_int(-(long)bc->len);
97145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (!jmp->target.abs)
97245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                jmp->target.abs = yasm_expr_create_ident(yasm_expr_int(delta),
97345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                                         bc->line);
97445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
97545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                jmp->target.abs =
97645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    yasm_expr_create(YASM_EXPR_ADD,
97745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                     yasm_expr_expr(jmp->target.abs),
97845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                     yasm_expr_int(delta), bc->line);
97945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
98045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            jmp->target.size = i*8;
98145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            jmp->target.sign = 1;
98245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (output_value(&jmp->target, *bufp, i,
983d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                             (unsigned long)(*bufp-bufstart), bc, 1, d))
98445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                return 1;
98545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            *bufp += i;
98645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
98745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        case JMP_NONE:
98845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_internal_error(N_("jump op_sel cannot be JMP_NONE in tobytes"));
98945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        default:
99045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_internal_error(N_("unrecognized relative jump op_sel"));
99145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
99245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
99345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
99445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
99545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgstatic int
996d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.orgx86_bc_jmpfar_tobytes(yasm_bytecode *bc, unsigned char **bufp,
997d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                      unsigned char *bufstart, void *d,
99845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      yasm_output_value_func output_value,
99945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                      /*@unused@*/ yasm_output_reloc_func output_reloc)
100045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
100145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_jmpfar *jmpfar = (x86_jmpfar *)bc->contents;
100245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned int i;
100345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char opersize;
100445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
100545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_common_tobytes(&jmpfar->common, bufp, 0);
100645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    x86_opcode_tobytes(&jmpfar->opcode, bufp);
100745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
100845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* As opersize may be 0, figure out its "real" value. */
100945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    opersize = (jmpfar->common.opersize == 0) ?
101045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        jmpfar->common.mode_bits : jmpfar->common.opersize;
101145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
101245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Absolute displacement: segment and offset */
101345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    i = (opersize == 16) ? 2 : 4;
101445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    jmpfar->offset.size = i*8;
101545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (output_value(&jmpfar->offset, *bufp, i,
1016d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                     (unsigned long)(*bufp-bufstart), bc, 1, d))
101745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 1;
101845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *bufp += i;
101945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    jmpfar->segment.size = 16;
102045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (output_value(&jmpfar->segment, *bufp, 2,
1021d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org                     (unsigned long)(*bufp-bufstart), bc, 1, d))
102245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 1;
102345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *bufp += 2;
102445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
102545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
102645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
102745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
102845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
102945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_x86__intnum_tobytes(yasm_arch *arch, const yasm_intnum *intn,
103045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                         unsigned char *buf, size_t destsize, size_t valsize,
103145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                         int shift, const yasm_bytecode *bc, int warn)
103245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
103345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Write value out. */
103445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_intnum_get_sized(intn, buf, destsize, valsize, shift, 0, warn);
103545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 0;
103645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
1037