#ifndef _ASM_X86_ALTERNATIVE_ASM_H_ #define _ASM_X86_ALTERNATIVE_ASM_H_ #include #ifdef __ASSEMBLY__ /* * Issue one struct alt_instr descriptor entry (need to put it into * the section .altinstructions, see below). This entry contains * enough information for the alternatives patching code to patch an * instruction. See apply_alternatives(). */ .macro altinstruction_entry orig, repl, feature, orig_len, repl_len, pad_len .if ((\feature) & ~ALT_FLAG_NOT) >= NCAPINTS * 32 .error "alternative feature outside of featureset range" .endif .long \orig - . .long \repl - . .word \feature .byte \orig_len .byte \repl_len .byte \pad_len .byte 0 /* priv */ .endm .macro mknops nr_bytes #ifdef HAVE_AS_NOPS_DIRECTIVE .nops \nr_bytes, ASM_NOP_MAX #else .skip \nr_bytes, 0x90 #endif .endm /* * GAS's idea of true is sometimes 1 and sometimes -1, while Clang's idea * was consistently 1 up to 6.x (it matches GAS's now). Transform it to * uniformly 1. */ #define as_true(x) ((x) & 1) #define decl_orig(insn, padding) \ .L\@_orig_s: insn; .L\@_orig_e: \ .L\@_diff = padding; \ mknops (as_true(.L\@_diff > 0) * .L\@_diff); \ .L\@_orig_p: #define orig_len (.L\@_orig_e - .L\@_orig_s) #define pad_len (.L\@_orig_p - .L\@_orig_e) #define total_len (.L\@_orig_p - .L\@_orig_s) #define decl_repl(insn, nr) .L\@_repl_s\()nr: insn; .L\@_repl_e\()nr: #define repl_len(nr) (.L\@_repl_e\()nr - .L\@_repl_s\()nr) #define clone_repl(new, old) .equiv .L\@_repl_s\()new, .L\@_repl_s\()old; \ .equiv .L\@_repl_e\()new, .L\@_repl_e\()old #define as_max(a, b) ((a) ^ (((a) ^ (b)) & -as_true((a) < (b)))) .macro ALTERNATIVE oldinstr, newinstr, feature decl_orig(\oldinstr, repl_len(1) - orig_len) .pushsection .altinstructions, "a", @progbits altinstruction_entry .L\@_orig_s, .L\@_repl_s1, \feature, \ orig_len, repl_len(1), pad_len .section .discard, "a", @progbits /* * Assembler-time checks: * - total_len <= 255 * - \newinstr <= total_len */ .byte total_len .byte 0xff + repl_len(1) - total_len .section .altinstr_replacement, "ax", @progbits decl_repl(\newinstr, 1) .popsection .endm .macro ALTERNATIVE_2 oldinstr, newinstr1, feature1, newinstr2, feature2 decl_orig(\oldinstr, as_max(repl_len(1), repl_len(2)) - orig_len) .pushsection .altinstructions, "a", @progbits altinstruction_entry .L\@_orig_s, .L\@_repl_s1, \feature1, \ orig_len, repl_len(1), pad_len altinstruction_entry .L\@_orig_s, .L\@_repl_s2, \feature2, \ orig_len, repl_len(2), pad_len .section .discard, "a", @progbits /* * Assembler-time checks: * - total_len <= 255 * - \newinstr* <= total_len */ .byte total_len .byte 0xff + repl_len(1) - total_len .byte 0xff + repl_len(2) - total_len .section .altinstr_replacement, "ax", @progbits decl_repl(\newinstr1, 1) .ifnes "\newinstr2", "\newinstr1" decl_repl(\newinstr2, 2) .else clone_repl(2, 1) .endif .popsection .endm #undef as_max #undef repl_len #undef decl_repl #undef total_len #undef pad_len #undef orig_len #undef decl_orig #undef as_true #endif /* __ASSEMBLY__ */ #endif /* _ASM_X86_ALTERNATIVE_ASM_H_ */ /* * Local variables: * mode: C * c-file-style: "BSD" * c-basic-offset: 4 * tab-width: 4 * indent-tabs-mode: nil * End: */