cosmopolitan/tool/build/helpop.c

373 lines
14 KiB
C
Raw Normal View History

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
#include "libc/bits/safemacros.internal.h"
#include "libc/fmt/conv.h"
#include "libc/macros.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/ex.h"
#include "libc/sysv/consts/exit.h"
#include "third_party/getopt/getopt.h"
#define USAGE \
" [FLAGS] OPERAND..\n\
Decodes geek operand notation used by ref.x86asm.net\n\
\n\
Flags:\n\
-s succinct mode\n\
-b BITS sets 16/32/64 bit mode [default 64]\n\
-? shows this information\n\
\n\
Examples:\n\
o/tool/cpu/help-operand -b64 Evqp\n\
\n"
int bits_;
bool succinct_;
void PrintUsage(int rc, FILE *f) {
fputs("Usage: ", f);
fputs(program_invocation_name, f);
fputs(USAGE, f);
exit(rc);
}
void GetOpts(int argc, char *argv[]) {
int opt;
bits_ = 64;
while ((opt = getopt(argc, argv, "?hbs")) != -1) {
switch (opt) {
case 's':
succinct_ = true;
break;
case 'b':
bits_ = atoi(optarg);
break;
case '?':
case 'h':
PrintUsage(EXIT_SUCCESS, stdout);
default:
PrintUsage(EX_USAGE, stderr);
}
}
}
const struct Descriptors {
const char prefix[8];
const char *succinct;
const char *description;
} kDescriptors[] = {
{"AL", "AL", "AL register"},
{"CS", "CS", "CS register (code segment)"},
{"va", "?",
"Word or doubleword, according to asz address-size attribute (only REP "
"and LOOP families)."},
{"dqa", "?",
"Doubleword or quadword, according to asz address-size attribute (only "
"REP and LOOP families)."},
{"wa", "?",
"Word, according to asz address-size attribute (only JCXZ instruction)."},
{"wo", "?",
"Word, according to current operand size (e. g., MOVSW instruction)."},
{"ws", "?",
"Word, according to current stack size (only PUSHF and POPF instructions "
"in 64-bit mode)."},
{"da", "?",
"Doubleword, according to asz address-size attribute (only JECXZ "
"instruction)."},
{"do", "?",
"Doubleword, according to current osz operand size (e. g., MOVSD "
"instruction)."},
{"qa", "?",
"Quadword, according to asz address-size attribute (only JRCXZ "
"instruction)."},
{"qs", "64/16",
"Quadword, according to current stack size via osz operand-size (only "
"PUSHFQ and POPFQ instructions)."},
{"va", "16/32",
"Word or doubleword sign extended to the size of the stack pointer (for "
"example, PUSH (68))."},
{"vqp", "16/32/64",
"Word or doubleword, depending on operand-size attribute, or "
"quadword, promoted by REX.W in 64-bit mode."},
{"vs", "16/32",
"Word or doubleword sign extended to the size of the stack pointer (for "
"example, PUSH (68))."},
{"vds", "16/32",
"Word or doubleword, depending on operand-size attribute, or doubleword, "
"sign-extended to 64 bits for 64-bit operand size."},
{"vq", "64/16",
"Quadword (default) or word if operand-size prefix is used (for "
"example, PUSH (50))."},
{"EST", "STi",
"A ModR/M byte follows the opcode and specifies the x87 FPU stack "
"register."},
{"ES", "STi/m",
"A ModR/M byte follows the opcode and specifies the operand. The "
"operand is either a x87 FPU stack register or a memory address. If "
"it is a memory address, the address is computed from a segment "
"register and any of the following values: a base register, an "
"index register, a scaling factor, or a displacement."},
{"SC", "",
"Stack operand, used by instructions which either push an operand to the "
"stack or pop an operand from the stack. Pop-like instructions are, for "
"example, POP, RET, IRET, LEAVE. Push-like are, for example, PUSH, CALL, "
"INT. No Operand type is provided along with this method because it "
"depends on source/destination operand(s)."},
{"BA", "m",
"Memory addressed by DS:EAX, or by rAX in 64-bit mode (only 0F01C8 "
"MONITOR)."},
{"BB", "m",
"Memory addressed by DS:eBX+AL, or by rBX+AL in 64-bit mode (only XLAT)."},
{"BD", "m",
"Memory addressed by DS:eDI or by RDI (only 0FF7 MASKMOVQ and 660FF7 "
"MASKMOVDQU)"},
{"A", "ptr",
"Direct address. The instruction has no ModR/M byte; the address of the "
"operand is encoded in the instruction; no base register, index register, "
"or scaling factor can be applied (for example, far JMP (EA))."},
{"C", "CRn",
"The reg field of the ModR/M byte selects a control register (only MOV "
"(0F20, 0F22))."},
{"D", "DRn",
"The reg field of the ModR/M byte selects a debug register (only MOV "
"(0F21, 0F23))."},
{"I", "imm",
"Immediate data. The operand value is encoded in subsequent bytes of the "
"instruction."},
{"J", "rel",
"The instruction contains a relative offset to be added to the "
"instruction pointer register (for example, JMP (E9), LOOP))."},
{"E", "r/m",
"A ModR/M byte follows the opcode and specifies the operand. The "
"operand is either a general-purpose register or a memory address. "
"If it is a memory address, the address is computed from a segment "
"register and any of the following values: a base register, an index "
"register, a scaling factor, or a displacement."},
{"G", "r",
"The reg field of the ModR/M byte selects a general register (for "
"example, AX (000))."},
{"H", "r",
"The r/m field of the ModR/M byte always selects a general register, "
"regardless of the mod field (for example, MOV (0F20))."},
{"M", "rm",
"The ModR/M byte may refer only to memory: mod != 11bin (BOUND, LEA, "
"CALLF, JMPF, LES, LDS, LSS, LFS, LGS, CMPXCHG8B, CMPXCHG16B, F20FF0 "
"LDDQU)."},
{"N", "mm",
"The R/M field of the ModR/M byte selects a packed quadword MMX "
"technology register."},
{"O", "moffs",
"The instruction has no ModR/M byte; the offset of the operand is coded "
"as a word, double word or quad word (depending on address size "
"attribute) in the instruction. No base register, index register, or "
"scaling factor can be applied (only MOV (A0, A1, A2, A3))."},
{"P", "mm",
"The reg field of the ModR/M byte selects a packed quadword MMX "
"technology register."},
{"Q", "mm/m64",
"A ModR/M byte follows the opcode and specifies the operand. The "
"operand is either an MMX technology register or a memory address. "
"If it is a memory address, the address is computed from a segment "
"register and any of the following values: a base register, an index "
"register, a scaling factor, and a displacement."},
{"R", "r",
"The mod field of the ModR/M byte may refer only to a general "
"register (only MOV (0F20-0F24, 0F26))."},
{"S", "Sreg",
"The reg field of the ModR/M byte selects a segment register (only MOV "
"(8C, 8E))."},
{"T", "TRn",
"The reg field of the ModR/M byte selects a test register (only MOV "
"(0F24, 0F26))."},
{"U", "xmm",
"The R/M field of the ModR/M byte selects a 128-bit XMM register."},
{"sr", "32real",
"Single-real. Only x87 FPU instructions (for example, FADD)."},
{"dr", "64real",
"Double-real. Only x87 FPU instructions (for example, FADD)."},
{"er", "80real",
"Extended-real. Only x87 FPU instructions (for example, FLD)."},
{"e", "14/28", "x87 FPU environment (for example, FSTENV)."},
{"V", "xmm",
"The reg field of the ModR/M byte selects a 128-bit XMM register."},
{"W", "xmm/m",
"A ModR/M byte follows the opcode and specifies the operand. The operand "
"is either a 128-bit XMM register or a memory address. If it is a memory "
"address, the address is computed from a segment register and any of the "
"following values: a base register, an index register, a scaling factor, "
"and a displacement"},
{"X", "m",
"Memory addressed by the DS:eSI or by RSI (only MOVS, CMPS, OUTS, "
"and LODS). In 64-bit mode, only 64-bit (RSI) and 32-bit (ESI) "
"address sizes are supported. In non-64-bit modes, only 32-bit (ESI) "
"and 16-bit (SI) address sizes are supported."},
{"Y", "m",
"Memory addressed by the ES:eDI or by RDI (only MOVS, CMPS, INS, "
"STOS, and SCAS). In 64-bit mode, only 64-bit (RDI) and 32-bit (EDI) "
"address sizes are supported. In non-64-bit modes, only 32-bit (EDI) "
"and 16-bit (DI) address sizes are supported. The implicit ES "
"segment register cannot be overriden by a segment prefix."},
{"Z", "r",
"The instruction has no ModR/M byte; the three least-significant "
"bits of the opcode byte selects a general-purpose register."},
{"F", "-", "rFLAGS register."},
{"si", "32real",
"Doubleword integer register (e. g., eax). (unused even by Intel?)"},
{"ss", "-",
"Scalar element of a 128-bit packed single-precision floating data."},
{"stx", "512", "x87 FPU and SIMD state (FXSAVE and FXRSTOR)."},
{"st", "94/108", "x87 FPU state (for example, FSAVE)."},
{"s", "-",
"6-byte pseudo-descriptor, or 10-byte pseudo-descriptor in 64-bit mode "
"(for example, SGDT)."},
{"bcd", "80dec",
"Packed-BCD. Only x87 FPU instructions (for example, FBLD)."},
{"bsq", "", "(Byte, sign-extended to 64 bits.)"},
{"bss", "8",
"Byte, sign-extended to the size of the stack pointer (for example, PUSH "
"(6A))."},
{"bs", "8", "Byte, sign-extended to the size of the destination operand."},
{"a", "16/32&16/32",
"Two one-word operands in memory or two double-word operands in memory, "
"depending on operand-size attribute (only BOUND)."},
{"b", "8", "Byte, regardless of operand-size attribute."},
{"c", "?",
"Byte or word, depending on operand-size attribute. (unused even by "
"Intel?)"},
{"dqp", "32/64",
"Doubleword, or quadword, promoted by REX.W in 64-bit mode (for example, "
"MOVSXD)."},
{"dq", "128",
"Double-quadword, regardless of operand-size attribute (for example, "
"CMPXCHG16B)."},
{"ds", "32",
"Doubleword, sign-extended to 64 bits (for example, CALL (E8)."},
{"di", "32int",
"Doubleword-integer. Only x87 FPU instructions (for example, FIADD)."},
{"d", "32", "Doubleword, regardless of operand-size attribute."},
{"qi", "64int",
"Qword-integer. Only x87 FPU instructions (for example, FILD)."},
{"qp", "64", "Quadword, promoted by REX.W (for example, IRETQ)."},
{"q", "64",
"Quadword, regardless of operand-size attribute (for example, CALL (FF "
"/2))."},
{"v", "16/32",
"Word or doubleword, depending on operand-size attribute (for example, "
"INC (40), PUSH (50))."},
{"wi", "16int",
"Word-integer. Only x87 FPU instructions (for example, FIADD)."},
{"w", "16",
"Word, regardless of operand-size attribute (for example, ENTER)."},
{"pi", "-", "Quadword MMX technology data."},
{"psq", "-", "64-bit packed single-precision floating-point data."},
{"pd", "-", "128-bit packed double-precision floating-point data."},
{"ps", "-", "128-bit packed single-precision floating-point data."},
{"ptp", "16:16/32/64",
"32-bit or 48-bit pointer, depending on operand-size attribute, or 80-bit "
"far pointer, promoted by REX.W in 64-bit mode (for example, "
"CALLF (FF /3))."},
{"p", "16:16/32",
"32-bit or 48-bit pointer, depending on operand-size attribute (for "
"example, CALLF (9A)."},
};
void HandleOperand(const char *op) {
int i;
bool found;
while (*op) {
found = false;
for (i = 0; i < ARRAYLEN(kDescriptors); ++i) {
if (startswith(op, kDescriptors[i].prefix)) {
found = true;
op += strlen(kDescriptors[i].prefix);
if (succinct_) {
printf("%s ", kDescriptors[i].succinct);
} else if (!isempty(kDescriptors[i].succinct) &&
strcmp(kDescriptors[i].succinct, "-") != 0 &&
strcmp(kDescriptors[i].succinct, "?") != 0) {
printf("%s (%s): %s\n", kDescriptors[i].prefix,
kDescriptors[i].succinct, kDescriptors[i].description);
} else {
printf("%s: %s\n", kDescriptors[i].prefix,
kDescriptors[i].description);
}
break;
}
}
if (!found) {
printf("%c?", *op);
if (succinct_) {
printf(" ");
} else {
printf("\n");
}
op++;
}
}
printf("\n");
}
int main(int argc, char *argv[]) {
int i;
GetOpts(argc, argv);
for (i = optind; i < argc; ++i) {
HandleOperand(argv[i]);
}
return 0;
}