A Manual for the Plan 9 assembler(Plan 9 汇编手册)

作者:Rob Pike

rob@plan9.bell-labs.com

翻译:Mustenaka

Plan9是Golang汇编语言,是进入高级Golang解决各种debug问题的必经之路,本文主要翻译Plan9的使用手册,并增加一些自己的看法和简介,原文地址https://9p.io/sys/doc/asm.html

Machines

There is an assembler for each of the MIPS, SPARC, Intel 386, AMD64, Power PC, and ARM. The 68020 assembler, 2a, (no longer distributed) is the oldest and in many ways the prototype. The assemblers are really just variations of a single program: they share many properties such as left-to-right assignment order for instruction operands and the synthesis of macro instructions such as MOVE to hide the peculiarities of the load and store structure of the machines. To keep things concrete, the first part of this manual is specifically about the 68020. At the end is a description of the differences among the other assemblers.

每个 MIPS、SPARC、Intel 386、AMD64、Power PC 和 ARM 都有一个汇编器。 68020 汇编器 ,2a(不再分发)是最古老的,并且在许多方面都是原型。 汇编程序实际上只是单个程序的变体:它们共享许多属性,例如指令操作数从左到右的分配顺序和宏指令的合成,例如 MOVE 以隐藏机器加载和存储结构的特性。 为了具体起见,本手册的第一部分专门针对 68020。最后是对其他汇编器之间差异的描述。

注:68020指的是1984年摩托罗拉发布的32位cpu,改进了早些时候的16位cpu和24位cpu的缺陷问题,一度流行成为一种标准,后基于此的汇编器演变发展出了各个新型编译器。

Registers

All pre-defined symbols in the assembler are upper-case. Data registers are R0 through R7; address registers are A0 through A7; floating-point registers are F0 through F7.

汇编程序中的所有预定义符号都是大写的。数据寄存器是R0到R7; 地址寄存器为A0到A7; 浮点寄存器从F0到F7。

A pointer in A6 is used by the C compiler to point to data, enabling short addresses to be used more often. The value of A6 is constant and must be set during C program initialization to the address of the externally-defined symbol a6base.

A6中的指针被C编译器用来指向数据,使短地址更经常地被使用。A6的值是恒定的,必须在C程序初始化时设置为外部定义的符号a6base的地址。

The following hardware registers are defined in the assembler; their meaning should be obvious given a 68020 manual: CAARCACRCCRDFCISPMSPSFCSRUSP, and VBR.

以下硬件寄存器在汇编程序中定义;对于68020手册,它们的含义应该很明显:CAAR、CACR、CCR、DFC、ISP、MSP、SFC、SR、USP和VBR。

The assembler also defines several pseudo-registers that manipulate the stack: FPSP, and TOSFP is the frame pointer, so 0(FP) is the first argument, 4(FP) is the second, and so on. SP is the local stack pointer, where automatic variables are held (SP is a pseudo-register only on the 68020); 0(SP) is the first automatic, and so on as with FP. Finally, TOS is the top-of-stack register, used for pushing parameters to procedures, saving temporary values, and so on.

汇编程序还定义了几个操作堆栈的伪寄存器:FP、SP和TOS。FP是帧指针,因此0(FP)是第一个参数,4(FP)是第二个参数,依此类推。SP是本地堆栈指针,其中保存自动变量(SP是只在68020上的伪寄存器);0(SP)是第一个自动,以此类推,FP也是如此。最后,TOS是栈顶寄存器,用于将参数推入过程、保存临时值等等。

The assembler and loader track these pseudo-registers so the above statements are true regardless of what has been pushed on the hardware stack, pointed to by A7. The name A7 refers to the hardware stack pointer, but beware of mixed use of A7 and the above stack-related pseudo-registers, which will cause trouble. Note, too, that the PEA instruction is observed by the loader to alter SP and thus will insert a corresponding pop before all returns. The assembler accepts a label-like name to be attached to FP and SP uses, such as p+0(FP), to help document that p is the first argument to a routine. The name goes in the symbol table but has no significance to the result of the program.

汇编器和加载器跟踪这些伪寄存器,因此无论硬件堆栈上推送了什么,上面的语句都是正确的,A7指出。名称A7指的是硬件堆栈指针,但要注意混合使用A7和上面与堆栈相关的伪寄存器,这会带来麻烦。还要注意,加载器会观察PEA指令来改变SP,因此会在所有返回之前插入相应的pop。汇编程序接受一个标签式的名称附加到FP上,SP使用(例如p+0(FP))来帮助说明p是例程的第一个参数。名称进入符号表,但对程序的结果没有意义。

PS:理解一下就是

R0 数据寄存器

A0 地址寄存器

F0 浮点寄存器

CAAR, CACR, 等特殊名字

$con 常量

$fcon 浮点数常量

name+o(SB) 外部符号

name<>+o(SB) 局部符号

name+o(SP) 自动符号

name+o(FP) 实际参数

$name+o(SB) 外部地址

$name<>+o(SB) 局部地址

(A0)+ 间接后增量

-(A0) 间接前增量

o(A0)

o()(R0.s)

Referring to data

All external references must be made relative to some pseudo-register, either PC (the virtual program counter) or SB (the ‘‘static base’’ register). PC counts instructions, not bytes of data. For example, to branch to the second following instruction, that is, to skip one instruction, one may write

所有外部引用都必须相对于某些伪寄存器进行,PC(虚拟程序计数器)或 SB(“静态基”寄存器)。 PC 计算指令,而不是数据字节。例如,跳转到第二条指令,即跳过一条指令,可以这样写

    BRA 2(PC)

Labels are also allowed, as in

标签也是允许的,比如

    BRA return

    NOP

return:

    RTS

When using labels, there is no (PC) annotation.

当使用标签时,没有(PC)注释。

The pseudo-register SB refers to the beginning of the address space of the program. Thus, references to global data and procedures are written as offsets to SB, as in

伪寄存器SB指的是程序地址空间的开头。因此,对全局数据和过程的引用被写入SB的偏移量,如

    MOVL    $array(SB), TOS

to push the address of a global array on the stack, or

将全局数组的地址推入堆栈,或

    MOVL    array+4(SB), TOS

to push the second (4-byte) element of the array. Note the use of an offset; the complete list of addressing modes is given below. Similarly, subroutine calls must use SB:

推入数组的第二个(4字节)元素。注意偏移量的使用;下面给出了寻址模式的完整列表。类似地,子例程调用必须使用SB:

    BSR exit(SB)

File-static variables have syntax

文件静态变量有语法

    local<>+4(SB)

The <> will be filled in at load time by a unique integer.

<>将在加载时由一个唯一的整数填充。

When a program starts, it must execute

当程序启动时,它必须执行

    MOVL    $a6base(SB), A6

before accessing any global data. (On machines such as the MIPS and SPARC that cannot load a register in a single instruction, constants are loaded through the static base register. The loader recognizes code that initializes the static base register and treats it specially. You must be careful, however, not to load large constants on such machines when the static base register is not set up, such as early in interrupt routines.)

在访问任何全局数据之前。(在MIPS和SPARC等不能在单个指令中加载寄存器的机器上,常量通过静态基寄存器加载。加载器识别初始化静态基寄存器的代码并对其进行特殊处理。但是,你必须小心,不要在静态基寄存器没有设置的情况下在这样的机器上加载大的常量,例如在中断例程的早期。)

Expressions

Expressions are mostly what one might expect. Where an offset or a constant is expected, a primary expression with unary operators is allowed. A general C constant expression is allowed in parentheses.

人们想要的大多是“表达式”,如果需要偏移量或常量,则允许使用带一元运算符的主表达式。一般的C语言常量表达式允许在括号中。

Source files are preprocessed exactly as in the C compiler, so #define and #include work.

源文件的预处理与C语言编译器中的完全相同,因此可以使用运行#define和#include。

Addressing modes

The simple addressing modes are shared by all the assemblers. Here, for completeness, follows a table of all the 68020 addressing modes, since that machine has the richest set. In the table, o is an offset, which if zero may be elided, and d is a displacement, which is a constant between -128 and 127 inclusive. Many of the modes listed have the same name; scrutiny of the format will show what default is being applied. For instance, indexed mode with no address register supplied operates as though a zero-valued register were used. For “offset” read “displacement.” For “.s” read one of .L, or .W followed by *1*2*4, or *8 to indicate the size and scaling of the data.

所有汇编程序共享简单寻址模式。这里,为了完整起见,下面是一个包含所有68020寻址模式的表,因为那台机器的寻址模式最丰富。在表中,o是一个偏移量,如果0可以省略,d是一个位移,它是-128到127之间的一个常数。列出的许多模式都有相同的名称;仔细检查格式将显示应用了什么默认值。例如,没有提供地址寄存器的索引模式就像使用了零值寄存器一样。对于“offset”,请阅读“displacement”。”。s”读取. l或. w后面跟着*1、*2、*4或*8中的一个,以表示数据的大小和伸缩。

Laying down data

Placing data in the instruction stream, say for interrupt vectors, is easy: the pseudo-instructions LONG and WORD (but not BYTE) lay down the value of their single argument, of the appropriate size, as if it were an instruction:

在指令流中放置数据,比如中断向量,很容易:伪指令LONG和WORD(但不是BYTE)将它们的单个参数的值设置为适当的大小,就像一条指令一样:

    LONG    $12345

places the long 12345 (base 10) in the instruction stream. (On most machines, the only such operator is WORD and it lays down 32-bit quantities. The 386 has all three: LONGWORD, and BYTE. The AMD64 adds QUAD to that for 64-bit values. The 960 has only one, LONG.)

在指令流中放置长12345(以10为基数)。(在大多数机器上,唯一这样的操作符是WORD,它规定32位的数量。386具备所有三种功能:LONG、WORD和BYTE。AMD64为64位值添加了QUAD。960只有一个,LONG。)

Placing information in the data section is more painful. The pseudo-instruction DATA does the work, given two arguments: an address at which to place the item, including its size, and the value to place there. For example, to define a character array array containing the characters abc and a terminating null:

在数据部分放置信息更加痛苦。伪指令DATA完成这项工作,给定两个参数:放置项的地址(包括其大小)和放置项的值。例如,定义一个包含字符abc和结束符null的字符数组:

    DATA    array+0(SB)/1, $’a’

    DATA    array+1(SB)/1, $’b’

    DATA    array+2(SB)/1, $’c’

    GLOBL   array(SB), $4

or

    DATA    array+0(SB)/4, $"abc\z"

    GLOBL   array(SB), $4

The /1 defines the number of bytes to define, GLOBL makes the symbol global, and the $4 says how many bytes the symbol occupies. Uninitialized data is zeroed automatically. The character \z is equivalent to the C \0. The string in a DATA statement may contain a maximum of eight bytes; build larger strings piecewise. Two pseudo-instructions, DYNT and INIT, allow the (obsolete) Alef compilers to build dynamic type information during the load phase. The DYNT pseudo-instruction has two forms:

/1定义要定义的字节数,GLOBL使符号成为全局的,$4表示符号占用的字节数。未初始化的数据将自动归零。字符\z相当于C \0。DATA语句中的字符串最多可以包含8个字节;分段构建更大的字符串。两个伪指令DYNT和INIT允许(过时的)Alef编译器在加载阶段构建动态类型信息。DYNT伪指令有两种形式:

    DYNT    , ALEF_SI_5+0(SB)

    DYNT    ALEF_AS+0(SB), ALEF_SI_5+0(SB)

In the first form, DYNT defines the symbol to be a small unique integer constant, chosen by the loader, which is some multiple of the word size. In the second form, DYNT defines the second symbol in the same way, places the address of the most recently defined text symbol in the array specified by the first symbol at the index defined by the value of the second symbol, and then adjusts the size of the array accordingly.

在第一种形式中,DYNT将符号定义为装入器选择的一个小的惟一整数常量,它是单词大小的若干倍。在第二种形式中,DYNT以同样的方式定义第二个符号,将第一个符号指定的数组中最近定义的文本符号的地址放在第二个符号的值定义的索引处,然后相应地调整数组的大小。

The INIT pseudo-instruction takes the same parameters as a DATA statement. Its symbol is used as the base of an array and the data item is installed in the array at the offset specified by the most recent DYNT pseudo-instruction. The size of the array is adjusted accordingly. The DYNT and INIT pseudo-instructions are not implemented on the 68020.

INIT伪指令接受与DATA语句相同的参数。它的符号被用作数组的基数,数据项被安装在由最新的DYNT伪指令指定的偏移位置的数组中。相应地调整数组的大小。DYNT和INIT伪指令没有在68020上实现。

Defining a procedure

Entry points are defined by the pseudo-operation TEXT, which takes as arguments the name of the procedure (including the ubiquitous (SB)) and the number of bytes of automatic storage to pre-allocate on the stack, which will usually be zero when writing assembly language programs. On machines with a link register, such as the MIPS and SPARC, the special value -4 instructs the loader to generate no PC save and restore instructions, even if the function is not a leaf. Here is a complete procedure that returns the sum of its two arguments:

入口点由伪操作TEXT定义,该操作将过程的名称(包括泛在(SB))和要预先分配到堆栈上的自动存储的字节数作为参数,在编写汇编语言程序时,字节数通常为零。在具有链接寄存器的机器上,如MIPS和SPARC,特殊值-4指示加载器不生成PC保存和恢复指令,即使该函数不是叶函数。下面是一个返回其两个参数的和的完整过程:

TEXT    sum(SB), $0

    MOVL    arg1+0(FP), R0

    ADDL    arg2+4(FP), R0

    RTS

An optional middle argument to the TEXT pseudo-op is a bit field of options to the loader. Setting the 1 bit suspends profiling the function when profiling is enabled for the rest of the program. For example,

TEXT伪运算的可选中间参数是加载器的选项位域。当为程序的其余部分启用分析时,设置1位将暂停分析函数。例如,

TEXT    sum(SB), 1, $0

    MOVL    arg1+0(FP), R0

    ADDL    arg2+4(FP), R0

    RTS

will not be profiled; the first version above would be. Subroutines with peculiar state, such as system call routines, should not be profiled.

不会被剖析;上面的第一个版本是。具有特殊状态的子例程,例如系统调用例程,不应该被分析。

Setting the 2 bit allows multiple definitions of the same TEXT symbol in a program; the loader will place only one such function in the image. It was emitted only by the Alef compilers.

设置2位允许在程序中对同一TEXT符号进行多个定义;加载器将只在图像中放置一个这样的函数。它只由Alef编译器发出。

Subroutines to be called from C should place their result in R0, even if it is an address. Floating point values are returned in F0. Functions that return a structure to a C program receive as their first argument the address of the location to store the result; R0 is unused in the calling protocol for such procedures. A subroutine is responsible for saving its own registers, and therefore is free to use any registers without saving them (‘‘caller saves’’). A6 and A7 are the exceptions as described above.

从C调用的子例程应该将结果放在R0中,即使它是一个地址。浮点值在F0中返回。向C程序返回结构的函数的第一个参数是存储结果的位置地址;R0在这类过程的调用协议中没有使用。子例程负责保存它自己的寄存器,因此可以自由使用任何寄存器而不保存它们(“调用者保存”)。如前所述,A6和A7是例外。

When in doubt

If you get confused, try using the -S option to 2c and compiling a sample program. The standard output is valid input to the assembler.

如果您感到困惑,请尝试对2c使用-S选项并编译一个示例程序。标准输出是汇编程序的有效输入。

Instructions

The instruction set of the assembler is not identical to that of the machine. It is chosen to match what the compiler generates, augmented slightly by specific needs of the operating system. For example, 2a does not distinguish between the various forms of MOVE instruction: move quick, move address, etc. Instead the context does the job. For example,

汇编程序的指令集与机器的指令集不相同。它的选择是为了匹配编译器生成的内容,并根据操作系统的特定需求稍微进行了扩充。例如,2a不区分各种形式的MOVE指令:MOVE quick, MOVE address等。相反,是环境在起作用。例如,

    MOVL    $1, R1

    MOVL    A0, R2

    MOVW    SR, R3

generates official MOVEQMOVEA, and MOVESR instructions. A number of instructions do not have the syntax necessary to specify their entire capabilities. Notable examples are the bitfield instructions, the multiply and divide instructions, etc. For a complete set of generated instruction names (in 2a notation, not Motorola’s) see the file /sys/src/cmd/2c/2.out.h. Despite its name, this file contains an enumeration of the instructions that appear in the intermediate files generated by the compiler, which correspond exactly to lines of assembly language.

生成官方的MOVEQ, MOVEA和MOVESR指令。许多指令没有指定其全部功能所需的语法。著名的例子是位域指令、乘法和除法指令等。要获得生成的完整指令名集(以2a表示法,而不是Motorola的表示法),请参阅文件/sys/src/cmd/2c/2.out.h。尽管名为此文件,但该文件包含编译器生成的中间文件中出现的指令枚举,这些指令与汇编语言的行完全对应。

Laying down instructions

The loader modifies the code produced by the assembler and compiler. It folds branches, copies short sequences of code to eliminate branches, and discards unreachable code. The first instruction of every function is assumed to be reachable. The pseudo-instruction NOP, which you may see in compiler output, means no instruction at all, rather than an instruction that does nothing. The loader discards all NOP’s.

加载器修改由汇编程序和编译器生成的代码。它折叠分支,复制短代码序列以消除分支,并丢弃不可访问的代码。每个函数的第一个指令都假设是可达的。您可能在编译器输出中看到的伪指令NOP意味着根本没有指令,而不是什么都不做的指令。加载器丢弃所有NOP。

To generate a true NOP instruction, or any other instruction not known to the assembler, use a WORD pseudo-instruction. Such instructions on RISCs are not scheduled by the loader and must have their delay slots filled manually.

要生成真正的NOP指令,或汇编程序不知道的任何其他指令,请使用WORD伪指令。risc上的这些指令不是由加载器调度的,必须手动填充它们的延迟槽。

MIPS

The registers are only addressed by number: R0 through R31R29 is the stack pointer; R30 is used as the static base pointer, the analogue of A6 on the 68020. Its value is the address of the global symbol setR30(SB). The register holding returned values from subroutines is R1. When a function is called, space for the first argument is reserved at 0(FP) but in C (not Alef) the value is passed in R1 instead.

寄存器只通过数字寻址:R0到R31。R29是堆栈指针;R30被用作静态基准指针,类似于68020上的A6。它的值是全局符号setR30(SB)的地址。保存子例程返回值的寄存器是R1。当函数被调用时,第一个参数的空间被保留在0(FP),但在C(不是Alef)中,该值被传递到R1中。

The loader uses R28 as a temporary. The system uses R26 and R27 as interrupt-time temporaries. Therefore none of these registers should be used in user code.

加载器使用R28作为临时对象。系统使用R26和R27作为中断时间临时变量。因此,在用户代码中不应该使用这些寄存器。

The control registers are not known to the assembler. Instead they are numbered registers M0M1, etc. Use this trick to access, say, STATUS:

汇编程序不知道控制寄存器。取而代之的是编号为M0、M1等的寄存器。使用这个技巧来访问,比如说,STATUS:

#define STATUS  12

    MOVW    M(STATUS), R1

Floating point registers are called F0 through F31. By convention, F24 must be initialized to the value 0.0, F26 to 0.5, F28 to 1.0, and F30 to 2.0; this is done by the operating system.

浮点寄存器称为F0到F31。按照约定,F24必须初始化为值0.0,F26初始化为0.5,F28初始化为1.0,F30初始化为2.0;这是由操作系统完成的。

The instructions and their syntax are different from those of the manufacturer’s manual. There are no lui and kin; instead there are MOVW (move word), MOVH (move halfword), and MOVB (move byte) pseudo-instructions. If the operand is unsigned, the instructions are MOVHU and MOVBU. The order of operands is from left to right in dataflow order, just as on the 68020 but not as in MIPS documentation. This means that the Bcond instructions are reversed with respect to the book; for example, a va BGTZ generates a MIPS bltz instruction.

说明书及其语法与制造商手册中的不同。没有lui和kin;取而代之的是MOVW(移动字)、MOVH(移动半字)和MOVB(移动字节)伪指令。如果操作数是无符号的,则指令是MOVHU和MOVBU。操作数的顺序在数据流顺序中从左到右,与68020上相同,但与MIPS文档不同。这意味着Bcond指令与书相反;例如,一个va BGTZ生成一个MIPS bltz指令。

The assembler is for the R2000, R3000, and most of the R4000 and R6000 architectures. It understands the 64-bit instructions MOVVMOVVLADDVADDVUSUBVSUBVUMULVMULVUDIVVDIVVUSLLVSRLV, and SRAV. The assembler does not have any cache, load-linked, or store-conditional instructions.

该汇编程序适用于R2000、R3000以及大多数R4000和R6000体系结构。它理解64位指令MOVV, MOVVL, ADDV, ADDVU, SUBV, SUBVU, MULV, MULVU, DIVV, DIVVU, SLLV, SRLV和SRAV。汇编程序没有任何缓存、加载链接或存储条件指令。

Some assembler instructions are expanded into multiple instructions by the loader. For example the loader may convert the load of a 32 bit constant into an lui followed by an ori.

一些汇编程序指令被加载器扩展为多个指令。例如,加载器可以将一个32位常量的加载转换为一个lui后跟一个ori。

Assembler instructions should be laid out as if there were no load, branch, or floating point compare delay slots; the loader will rearrange—schedule—the instructions to guarantee correctness and improve performance. The only exception is that the correct scheduling of instructions that use control registers varies from model to model of machine (and is often undocumented) so you should schedule such instructions by hand to guarantee correct behavior. The loader generates

汇编程序指令的布局应该像没有负载、分支或浮点比较延迟槽一样;加载器将重新安排-调度-指令,以确保正确性和提高性能。唯一的例外是,使用控制寄存器的指令的正确调度因机器的不同模型而不同(而且通常没有文档记录),因此您应该手动调度此类指令以确保正确的行为。加载器生成

    NOR R0, R0, R0

when it needs a true no-op instruction. Use exactly this instruction when scheduling code manually; the loader recognizes it and schedules the code before it and after it independently. Also, WORD pseudo-ops are scheduled like no-ops.

当它需要一个真正的无操作指令时。在手动调度代码时完全使用此指令;加载器识别它,并在它之前和之后分别调度代码。另外,WORD伪操作被安排为无操作。

The NOSCHED pseudo-op disables instruction scheduling (scheduling is enabled by default); SCHED re-enables it. Branch folding, code copying, and dead code elimination are disabled for instructions that are not scheduled.

NOSCHED伪运算禁止指令调度(调度在默认情况下是启用的);SCHED重新启用它。对于未计划的指令,将禁用分支折叠、代码复制和死代码消除。

SPARC

Once you understand the Plan 9 model for the MIPS, the SPARC is familiar. Registers have numerical names only: R0 through R31. Forget about register windows: Plan 9 doesn’t use them at all. The machine has 32 global registers, period. R1 [sic] is the stack pointer. R2 is the static base register, with value the address of setSB(SB)R7 is the return register and also the register holding the first argument to a C (not Alef) function, again with space reserved at 0(FP)R14 is the loader temporary.

一旦您理解了MIPS的Plan 9模型,就熟悉了SPARC。寄存器只有数字名称:R0到R31。忘记寄存器窗口吧:plan 9根本不使用它们。这台机器有32个全局寄存器。R1 [sic]是堆栈指针。R2是静态基寄存器,值为setSB(SB)的地址。R7是返回寄存器,也是保存C(不是Alef)函数的第一个参数的寄存器,同样保留空间为0(FP)。R14是临时加载器。

Floating-point registers are exactly as on the MIPS.

浮点寄存器与MIPS上的寄存器完全相同。

The control registers are known by names such as FSR. The instructions to access these registers are MOVW instructions, for example

控制寄存器有诸如FSR之类的名称。例如,访问这些寄存器的指令是MOVW指令

    MOVW    Y, R8

for the SPARC instruction

的SPARC指令

    rdy %r8

Move instructions are similar to those on the MIPS: pseudo-operations that turn into appropriate sequences of sethi instructions, adds, etc. Instructions read from left to right. Because the arguments are flipped to SUBCC, the condition codes are not inverted as on the MIPS.

Move指令类似于MIPS上的指令:转换为适当序列的sethi指令、添加指令等的伪操作。说明从左到右读。因为参数被翻转到SUBCC,所以条件代码不像在MIPS上那样被颠倒。

The syntax for the ASI stuff is, for example to move a word from ASI 2:

ASI的语法是这样的,例如从ASI 2中移动一个单词:

    MOVW    (R7, 2), R8

The syntax for double indexing is

双索引的语法是

    MOVW    (R7+R8), R9

The SPARC’s instruction scheduling is similar to the MIPS’s. The official no-op instruction is:

SPARC的指令调度与MIPS的类似。官方的无操作说明是:

    ORN R0, R0, R0

i960

Registers are numbered R0 through R31. Stack pointer is R29; return register is R4; static base is R28; it is initialized to the address of setSB(SB)R3 must be zero; this should be done manually early in execution by

寄存器编号为R0到R31。堆栈指针为R29;返回寄存器为R4;静态底座为R28;它被初始化为setSB(SB)的地址。R3必须是零;这应该在执行的早期手动完成

    SUBO    R3, R3

R27 is the loader temporary.

R27是临时加载器。

There is no support for floating point.

不支持浮点数。

The Intel calling convention is not supported and cannot be used; use BAL instead. Instructions are mostly as in the book. The major change is that LOAD and STORE are both called MOV. The extension character for MOV is as in the manual: O for ordinal, W for signed, etc.

不支持Intel调用约定,不能使用;使用BAL代替。说明书和书上的内容差不多。主要的变化是LOAD和STORE都称为MOV。MOV的扩展字符与手册中一样:O表示序数,W表示有符号,等等。

i386

The assembler assumes 32-bit protected mode. The register names are SPAXBXCXDXBPDI, and SI. The stack pointer (not a pseudo-register) is SP and the return register is AX. There is no physical frame pointer but, as for the MIPS, FP is a pseudo-register that acts as a frame pointer.

汇编程序采用32位保护模式。寄存器名称为SP、AX、BX、CX、DX、BP、DI和SI。堆栈指针(不是伪寄存器)是SP,返回寄存器是AX。没有物理帧指针,但是对于MIPS来说,FP是一个充当帧指针的伪寄存器。

Opcode names are mostly the same as those listed in the Intel manual with an LW, or B appended to identify 32-bit, 16-bit, and 8-bit operations. The exceptions are loads, stores, and conditionals. All load and store opcodes to and from general registers, special registers (such as CR0, CR3, GDTR, IDTR, SS, CS, DS, ES, FS, and GS) or memory are written as

操作码名称大多与英特尔手册中列出的操作码名称相同,只是附加了L、W或B来标识32位、16位和8位操作。例外是加载、存储和条件。所有向通用寄存器、特殊寄存器(如CR0、CR3、GDTR、IDTR、SS、CS、DS、ES、FS和GS)或内存的加载和存储操作码都写为

    MOVx    src,dst

where x is LW, or B. Thus to get AL use a MOVB instruction. If you need to access AH, you must mention it explicitly in a MOVB:

其中x是L, W或b,因此要获得AL使用MOVB指令。如果你需要访问AH,你必须在MOVB中显式地提到它:

    MOVB    AH, BX

There are many examples of illegal moves, for example,

非法移动的例子有很多,例如,

    MOVB    BP, DI

that the loader actually implements as pseudo-operations.

加载器实际实现为伪操作。

The names of conditions in all conditional instructions (JSET) follow the conventions of the 68020 instead of those of the Intel assembler: JOSJOCJCSJCCJEQJNEJLSJHIJMIJPLJPSJPCJLTJGEJLE, and JGT instead of JOJNOJBJNBJZJNZJBEJNBEJSJNSJPJNPJLJNLJLE, and JNLE.

所有条件指令(J, SET)中的条件名称都遵循68020的约定,而不是英特尔汇编程序的约定:JOS, JOC, JCS, JCC, JEQ, JNE, JLS, JHI, JMI, JPL, JPS, JPC, JLT, JGE, JLE, JGT,而不是JO, JNO, JB, JNB, JZ, JNZ, JBE, JNBE, JS, JNS, JP, JNP, JL, JNL, JLE,和JNLE。

The addressing modes have syntax like AX(AX)(AX)(BX*4)10(AX), and 10(AX)(BX*4). The offsets from AX can be replaced by offsets from FP or SB to access names, for example extern+5(SB)(AX*2).

寻址模式的语法类似于AX、(AX)、(AX)(BX*4)、10(AX)和10(AX)(BX*4)。来自AX的偏移量可以被来自FP或SB的访问名称的偏移量替换,例如extern+5(SB)(AX*2)。

Other notes: Non-relative JMP and CALL have a * added to the syntax. Only LOOPLOOPEQ, and LOOPNE are legal loop instructions. Only REP and REPN are recognized repeaters. These are not prefixes, but rather stand-alone opcodes that precede the strings, for example

其他注意事项:非相对JMP和CALL在语法中添加了*。只有LOOP、LOOPEQ和LOOPNE是合法的循环指令。只有REP和REPN是可识别的中继器。例如,这些不是前缀,而是位于字符串前面的独立操作码

    CLD; REP; MOVSL

Segment override prefixes in MOD/RM fields are not supported.

不支持MOD/RM字段中的段覆盖前缀。

AMD64

The assembler assumes 64-bit mode unless a MODE pseudo-operation is given:

汇编程序假定64位模式,除非给出了mode伪操作:

    MODE $32

to change to 32-bit mode. The effect is mainly to diagnose instructions that are illegal in the given mode, but the loader will also assume 32-bit operands and addresses, and 32-bit PC values for call and return. The assembler’s conventions are similar to those for the 386, above. The architecture provides extra fixed-point registers R8 to R15. All registers are 64 bit, but instructions access low-order 8, 16 and 32 bits as described in the processor handbook. For example, MOVL to AX puts a value in the low-order 32 bits and clears the top 32 bits to zero. Literal operands are limited to signed 32 bit values, which are sign-extended to 64 bits in 64 bit operations; the exception is MOVQ, which allows 64-bit literals. The external registers in Plan 9’s C are allocated from R15 down.

切换到32位模式。其作用主要是诊断在给定模式中非法的指令,但加载器也将假定32位操作数和地址,以及32位PC值用于调用和返回。汇编程序的约定类似于上面386的约定。该体系结构提供了额外的定点寄存器R8到R15。所有的寄存器都是64位的,但是处理器手册中描述的指令访问低阶8位、16位和32位。例如,MOVL to AX将一个值放入低阶32位,并将前32位清除为零。文字操作数仅限于有符号的32位值,在64位操作中符号扩展为64位;例外是MOVQ,它允许64位文字。计划9的C中的外部寄存器从R15向下分配。

There are many new instructions, including the MMX and XMM media instructions, and conditional move instructions. MMX registers are M0 to M7, and XMM registers are X0 to X15. As with the 386 instruction names, all new 64-bit integer instructions, and the MMX and XMM instructions uniformly use L for ‘long word’ (32 bits) and Q for ‘quad word’ (64 bits). Some instructions use O (‘octword’) for 128-bit values, where the processor handbook variously uses O or DQ. The assembler also consistently uses PL for ‘packed long’ in XMM instructions, instead of QDQ or PI. Either MOVL or MOVQ can be used to move values to and from control registers, even when the registers might be 64 bits. The assembler often accepts the handbook’s name to ease conversion of existing code (but remember that the operand order is uniformly source then destination).

有许多新的指令,包括MMX和XMM媒体指令,以及有条件的移动指令。MMX寄存器是M0到M7, XMM寄存器是X0到X15。与386指令名一样,所有新的64位整数指令,以及MMX和XMM指令统一使用L表示“长字”(32位),使用Q表示“四字”(64位)。有些指令使用O (‘ octword ‘)表示128位的值,而处理器手册则使用O或DQ。汇编程序还一致地在XMM指令中使用PL来表示“包装长”,而不是Q、DQ或PI。无论是MOVL还是MOVQ都可以用于在控制寄存器之间移动值,甚至当寄存器可能是64位时也是如此。汇编程序通常接受手册的名称,以简化现有代码的转换(但请记住,操作数顺序是统一的源后目标顺序)。

C’s long long type is 64 bits, but passed and returned by value, not by reference. More notably, C pointer values are 64 bits, and thus long long and unsigned long long are the only integer types wide enough to hold a pointer value. The C compiler and library use the XMM floating-point instructions, not the old 387 ones, although the latter are implemented by assembler and loader. Unlike the 386, the first integer or pointer argument is passed in a register, which is BP for an integer or pointer (it can be referred to in assembly code by the pseudonym RARG). AX holds the return value from subroutines as before. Floating-point results are returned in X0, although currently the first floating-point parameter is not passed in a register. All parameters less than 8 bytes in length have 8 byte slots reserved on the stack to preserve alignment and simplify variable-length argument list access, including the first parameter when passed in a register, even though bytes 4 to 7 are not initialized.

C语言的long – long类型是64位,但是通过值传递和返回,而不是通过引用。更值得注意的是,C指针值是64位的,因此long long和unsigned long long是惟一宽度足够容纳指针值的整数类型。C编译器和库使用XMM浮点指令,而不是旧的387浮点指令,尽管后者是由汇编器和加载器实现的。与386不同的是,第一个整数或指针参数在寄存器中传递,它是整数或指针的BP(它可以在程序集代码中通过化名RARG引用)。AX像以前一样保存子例程的返回值。在X0中返回浮点结果,尽管目前没有在寄存器中传递第一个浮点参数。所有长度小于8字节的形参都在堆栈上保留8个字节槽,以保持对齐并简化变长实参列表访问,包括在寄存器中传递的第一个形参,即使字节4到7没有初始化。

Power PC

The Power PC follows the Plan 9 model set by the MIPS and SPARC, not the elaborate ABIs. The 32-bit instructions of the 60x and 8xx PowerPC architectures are supported; there is no support for the older POWER instructions. Registers are R0 through R31R0 is initialized to zero; this is done by C start up code and assumed by the compiler and loader. R1 is the stack pointer. R2 is the static base register, with value the address of setSB(SB)R3 is the return register and also the register holding the first argument to a C function, with space reserved at 0(FP) as on the MIPS. R31 is the loader temporary. The external registers in Plan 9’s C are allocated from R30 down.

Power PC遵循MIPS和SPARC设置的计划9模型,而不是精心设计的abi。支持60x和8xx PowerPC架构的32位指令;不支持旧的POWER指令。寄存器从R0到R31。R0初始化为零;这是由C启动代码完成的,并由编译器和加载器承担。R1是堆栈指针。R2是静态基寄存器,值为setSB(SB)的地址。R3是返回寄存器,也是保存C函数第一个参数的寄存器,与MIPS上一样,空间保留在0(FP)。R31是临时加载器。计划9的C中的外部寄存器从R30向下分配。

Floating point registers are called F0 through F31. By convention, several registers are initialized to specific values; this is done by the operating system. F27 must be initialized to the value 0x4330000080000000 (used by float-to-int conversion), F28 to the value 0.0, F29 to 0.5, F30 to 1.0, and F31 to 2.0.

浮点寄存器称为F0到F31。按照约定,几个寄存器被初始化为特定的值;这是由操作系统完成的。F27必须初始化为值0x4330000080000000(用于浮点到整数转换),F28初始化为值0.0,F29初始化为0.5,F30初始化为1.0,F31初始化为2.0。

As on the MIPS and SPARC, the assembler accepts arbitrary literals as operands to MOVW, and also to ADD and others where ‘immediate’ variants exist, and the loader generates sequences of addiaddisoris, etc. as required. The register indirect addressing modes use the same syntax as the SPARC, including double indexing when allowed.

就像在MIPS和SPARC上一样,汇编程序接受任意的字面量作为MOVW的操作数,也接受ADD和其他存在“直接”变体的操作数,加载程序根据需要生成addi、addis、oris等序列。寄存器间接寻址模式使用与SPARC相同的语法,包括允许的双索引。

The instruction names are generally derived from the Motorola ones, subject to slight transformation: the ‘.’ marking the setting of condition codes is replaced by CC, and when the letter ‘o’ represents ‘OE=1’ it is replaced by V. Thus addaddo. and subfzeo. become ADDADDVCC and SUBFZEVCC. As well as the three-operand conditional branch instruction BC, the assembler provides pseudo-instructions for the common cases: BEQBNEBGTBGEBLTBLEBVC, and BVS. The unconditional branch instruction is BR. Indirect branches use (CTR) or (LR) as target.

指令名称通常来自摩托罗拉的名称,稍加改变:’。’标记条件代码的设置用CC代替,当字母“o”表示“OE=1”时用v代替,即add, addo。和subfzeo。变成ADD, ADDVCC和SUBFZEVCC。除了三操作数条件分支指令BC之外,汇编程序还为常见情况提供伪指令:BEQ、BNE、BGT、BGE、BLT、BLE、BVC和BVS。无条件的分支指令是BR。间接分支使用(CTR)或(LR)作为目标。

Load or store operations are replaced by MOV variants in the usual way: MOVW (move word), MOVH (move halfword with sign extension), and MOVB (move byte with sign extension, a pseudo-instruction), with unsigned variants MOVHZ and MOVBZ, and byte-reversing MOVWBR and MOVHBR. ‘Load or store with update’ versions are MOVWUMOVHU, and MOVBZU. Load or store multiple is MOVMW. The exceptions are the string instructions, which are LSW and STSW, and the reservation instructions lwarx and stwcx., which are LWAR and STWCCC, all with operands in the usual data-flow order. Floating-point load or store instructions are FMOVDFMOVDUFMOVS, and FMOVSU. The register to register move instructions fmr and fmr. are written FMOVD and FMOVDCC.

加载或存储操作以通常的方式被MOV变量替换:MOVW(移动单词)、MOVH(移动带符号扩展的半词)和MOVB(移动带符号扩展的字节,一种伪指令)、无符号变量MOVHZ和MOVBZ以及字节反转MOVWBR和MOVHBR。“加载或存储与更新”的版本是MOVWU, MOVHU和MOVBZU。加载或存储倍数为MOVMW。例外是字符串指令,它们是LSW和STSW,以及预订指令lwarx和stwcx。,分别是LWAR和STWCCC,它们的操作数都按照通常的数据流顺序。浮点加载或存储指令有FMOVD、FMOVDU、FMOVS和FMOVSU。寄存器用于注册移动指令fmr和fmr。格式为FMOVD和FMOVDCC。

The assembler knows the commonly used special purpose registers: CRCTRDECLRMSR, and XER. The rest, which are often architecture-dependent, are referenced as SPR(n). The segment registers of the 60x series are similarly SEG(n), but n can also be a register name, as in SEG(R3). Moves between special purpose registers and general purpose ones, when allowed by the architecture, are written as MOVW, replacing mfcrmtcrmfmsrmtmsrmtsprmfsprmftb, and many others.

汇编程序知道常用的特殊用途寄存器:CR、CTR、DEC、LR、MSR和XER。其余的通常依赖于体系结构,称为SPR(n)。60x系列的段寄存器类似于SEG(n),但n也可以是寄存器名,如SEG(R3)。在架构允许的情况下,特殊用途寄存器和通用用途寄存器之间的移动被写为MOVW,取代mfcr、mtcr、mfmsr、mtmsr、mtspr、mfspr、mftb和许多其他寄存器。

The fields of the condition register CR are referenced as CR(0) through CR(7). They are used by the MOVFL (move field) pseudo-instruction, which produces mcrf or mtcrf. For example:

条件寄存器CR的字段被引用为CR(0)到CR(7)。它们被MOVFL(移动字段)伪指令使用,它产生mcrf或mtcrf。例如:

    MOVFL   CR(3), CR(0)

    MOVFL   R3, CR(1)

    MOVFL   R3, $7, CR

They are also accepted in the conditional branch instruction, for example

例如,它们在条件分支指令中也被接受

    BEQ CR(7), label

Fields of the FPSCR are accessed using MOVFL in a similar way:

使用MOVFL以类似的方式访问FPSCR的字段:

    MOVFL   FPSCR, F0

    MOVFL   F0, FPSCR

    MOVFL   F0, $7, FPSCR

    MOVFL   $0, FPSCR(3)

producing mffsmtfsf or mtfsfi, as appropriate.

产生mffs, mtfsf或mtfsfi,视情况而定。

ARM

The assembler provides access to R0 through R14 and the PC. The stack pointer is R13, the link register is R14, and the static base register is R12R0 is the return register and also the register holding the first argument to a subroutine. The external registers in Plan 9’s C are allocated from R10 down. R11 is used by the loader as a temporary register. The assembler supports the CPSR and SPSR registers. It also knows about coprocessor registers C0 through C15. Floating registers are F0 through F7FPSR and FPCR.

汇编程序通过R14提供对R0和PC的访问。堆栈指针是R13,链接寄存器是R14,静态基寄存器是R12。R0是返回寄存器,也是保存子例程第一个参数的寄存器。计划9的C中的外部寄存器是从R10向下分配的。R11被加载器用作临时寄存器。汇编程序支持CPSR和SPSR寄存器。它还知道协处理器寄存器C0到C15。浮动寄存器是F0到F7, FPSR和FPCR。

As with the other architectures, loads and stores are called MOV, e.g. MOVW for load word or store word, and MOVM for load or store multiple, depending on the operands.

与其他体系结构一样,加载和存储被称为MOV,例如,MOVW用于加载字或存储字,MOVM用于加载或存储多个,这取决于操作数。

Addressing modes are supported by suffixes to the instructions: .IA (increment after), .IB (increment before), .DA (decrement after), and .DB (decrement before). These can only be used with the MOV instructions. The move multiple instruction, MOVM, defines a range of registers using brackets, e.g. [R0-R12]. The special MOVM addressing mode bits WU, and P are written in the same manner, for example, MOVM.DB.W. A .S suffix allows a MOVM instruction to access user R13 and R14 when in another processor mode. Shifts and rotates in addressing modes are supported by binary operators << (logical left shift), >> (logical right shift), -> (arithmetic right shift), and @> (rotate right); for example R7>>R2or R2@>2. The assembler does not support indexing by a shifted expression; only names can be doubly indexed.

寻址模式由指令的后缀支持:. ia(后面的增量),. ib(前面的增量),. da(后面的递减)和. db(前面的递减)。这些只能与MOV指令一起使用。移动多重指令MOVM使用括号定义了一个寄存器范围,例如[R0-R12]。特殊的MOVM寻址模式位W、U和P以同样的方式写入,例如,MOVM. db .W。s后缀允许MOVM指令在另一种处理器模式下访问用户R13和R14。寻址模式中的移位和旋转由二进制运算符&lt;&lt;(逻辑左移),&gt;&gt;(逻辑右移),-&gt;(算术右移),@&gt;(向右旋转);例如R7&gt;&gt; r2或R2@&gt;汇编程序不支持用移位的表达式进行索引;只有名称可以被双索引。

Any instruction can be followed by a suffix that makes the instruction conditional: .EQ.NE, and so on, as in the ARM manual, with synonyms .HS (for .CS) and .LO (for .CC), for example ADD.NE. Arithmetic and logical instructions can have a .S suffix, as ARM allows, to set condition codes.

任何指令后面都可以跟一个后缀,使该指令具有条件:. eq, . ne等等,如ARM手册中所示,还有同义词。hs(表示。cs)和。lo(表示。cc),例如ADD.NE。算术和逻辑指令可以有一个. s后缀,因为ARM允许,用来设置条件代码。

The syntax of the MCR and MRC coprocessor instructions is largely as in the manual, with the usual adjustments. The assembler directly supports only the ARM floating-point coprocessor operations used by the compiler: CMPADDSUBMUL, and DIV, all with F or D suffix selecting single or double precision. Floating-point load or store become MOVF and MOVD. Conversion instructions are also specified by moves: MOVWDMOVWFMOVDWMOVWDMOVFD, and MOVDF.

MCR和MRC协处理器指令的语法在很大程度上与手册中的一样,只是进行了通常的调整。汇编程序直接支持编译器使用的ARM浮点协处理器操作:CMP、ADD、SUB、MUL和DIV,所有这些操作都带有F或D后缀选择单精度或双精度。浮点加载或存储变成了MOVF和MOVD。转换指令也由move指定:MOVWD, MOVWF, MOVDW, MOVWD, MOVFD和MOVDF。

分类: Go

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注