9.16.2 x86 specific Directives

.lcomm symbol , length[, alignment]

Reserve length (an absolute expression) bytes for a local common denoted by symbol. The section and value of symbol are those of the new local common. The addresses are allocated in the bss section, so that at run-time the bytes start off zeroed. Since symbol is not declared global, it is normally not visible to ld. The optional third parameter, alignment, specifies the desired alignment of the symbol in the bss section.

This directive is only available for COFF based x86 targets.

.largecomm symbol , length[, alignment]

This directive behaves in the same way as the comm directive except that the data is placed into the .lbss section instead of the .bss section .comm symbol , length .

The directive is intended to be used for data which requires a large amount of space, and it is only available for ELF based x86_64 targets.

.value expression [, expression]

This directive behaves in the same way as the .short directive, taking a series of comma separated expressions and storing them as two-byte wide values into the current section.

.insn [prefix[,...]] [encoding] major-opcode[+r|/extension] [,operand[,...]]

This directive allows composing instructions which as may not know about yet, or which it has no way of expressing (which can be the case for certain alternative encodings). It assumes certain basic structure in how operands are encoded, and it also only recognizes - with a few extensions as per below - operands otherwise valid for instructions. Therefore there is no guarantee that everything can be expressed (e.g. the original Intel Xeon Phi’s MVEX encodings cannot be expressed).

  • prefix expresses one or more opcode prefixes in the usual way. Legacy encoding prefixes altering meaning (0x66, 0xF2, 0xF3) may be specified as high byte of <major-opcode> (perhaps already including an encoding space prefix). Note that there can only be one such prefix. Segment overrides are better specified in the respective memory operand, as long as there is one.
  • encoding is used to specify VEX, XOP, or EVEX encodings. The syntax tries to resemble that used in documentation:
    • VEX[.len][.prefix][.space][.w]
    • EVEX[.len][.prefix][.space][.w]
    • XOPspace[.len][.prefix][.w]

    Here

    • len can be LIG, 128, 256, or (EVEX only) 512 as well as L0 / L1 for VEX / XOP and L0...L3 for EVEX
    • prefix can be NP, 66, F3, or F2
    • space can be
      • 0f, 0f38, 0f3a, or M0...M31 for VEX
      • 08...1f for XOP
      • 0f, 0f38, 0f3a, or M0...M15 for EVEX
    • w can be WIG, W0, or W1

    Defaults:

    • Omitted len means "infer from operand size" if there is at least one sized vector operand, or LIG otherwise. (Obviously len has to be omitted when there’s EVEX rounding control specified later in the operands.)
    • Omitted prefix means NP.
    • Omitted space (VEX/EVEX only) implies encoding space is taken from major-opcode.
    • Omitted w means "infer from GPR operand size" in 64-bit code if there is at least one GPR(-like) operand, or WIG otherwise.
  • major-opcode is an absolute expression specifying the instruction opcode. Legacy encoding prefixes altering encoding space (0x0f, 0x0f38, 0x0f3a) have to be specified as high byte(s) here. "Degenerate" ModR/M bytes, as present in e.g. certain FPU opcodes or sub-spaces like that of major opcode 0x0f01, generally want encoding as immediate operand (such opcodes wouldn’t normally have non-immediate operands); in some cases it may be possible to also encode these as low byte of the major opcode, but there are potential ambiguities. Also note that after stripping encoding prefixes, the residual has to fit in two bytes (16 bits). +r can be suffixed to the major opcode expression to specify register-only encoding forms not using a ModR/M byte. /extension can alternatively be suffixed to the major opcode expression to specify an extension opcode, encoded in bits 3-5 of the ModR/M byte.
  • operand is an instruction operand expressed the usual way. Register operands are primarily used to express register numbers as encoded in ModR/M byte and REX/VEX/XOP/EVEX prefixes. In certain cases the register type (really: size) is also used to derive other encoding attributes, if these aren’t specified explicitly. Note that there is no consistency checking among operands, so entirely bogus mixes of operands are possible. Note further that only operands actually encoded in the instruction should be specified. Operands like ‘%cl’ in shift/rotate instructions have to be omitted, or else they’ll be encoded as an ordinary (register) operand. Operand order may also not match that of the actual instruction (see below).

Encoding of operands: While for a memory operand (of which there can be only one) it is clear how to encode it in the resulting ModR/M byte, register operands are encoded strictly in this order (operand counts do not include immediate ones in the enumeration below, and if there was an extension opcode specified it counts as a register operand; VEX.vvvv is meant to cover XOP and EVEX as well):

  • VEX.vvvv for 1-register-operand VEX/XOP/EVEX insns,
  • ModR/M.rm, ModR/M.reg for 2-operand insns,
  • ModR/M.rm, VEX.vvvv, ModR/M.reg for 3-operand insns, and
  • Imm{4,5}, ModR/M.rm, VEX.vvvv, ModR/M.reg for 4-operand insns,

obviously with the ModR/M.rm slot skipped when there is a memory operand, and obviously with the ModR/M.reg slot skipped when there is an extension opcode. For Intel syntax of course the opposite order applies. With +r (and hence no ModR/M) there can only be a single register operand for legacy encodings. VEX and alike can have two register operands, where the second (first in Intel syntax) would go into VEX.vvvv.

Immediate operands (including immediate-like displacements, i.e. when not part of ModR/M addressing) are emitted in the order specified, regardless of AT&T or Intel syntax. Since it may not be possible to infer the size of such immediates, they can be suffixed by {:sn} or {:un}, representing signed / unsigned immediates of the given number of bits respectively. When emitting such operands, the number of bits will be rounded up to the smallest suitable of 8, 16, 32, or 64. Immediates wider than 32 bits are permitted in 64-bit code only.

For EVEX encoding memory operands with a displacement need to know Disp8 scaling size in order to use an 8-bit displacement. For many instructions this can be inferred from the types of other operands specified. In Intel syntax ‘DWORD PTR’ and alike can be used to specify the respective size. In AT&T syntax the memory operands can be suffixed by {:dn} to specify the size (in bytes). This can be combined with an embedded broadcast specifier: ‘8(%eax){1to8:d8}’.