首页 文章

设计AT&T汇编语法的最初原因是什么? [关闭]

提问于
浏览
5

在x86或amd64上使用汇编指令时,程序员可以使用"Intel"(即 nasm 编译器)或"AT&T"(即 gas 编译器)汇编语法 . "Intel"语法在Windows上更受欢迎,但"AT&T"在UNIX(类似)系统上更受欢迎 .

但是,英特尔和AMD的手册,以及芯片创建者创建的手册都使用“英特尔”语法 .

我想知道,“AT&T”语法设计背后的原始想法是什么?浮动处理器创建者使用的符号有什么好处?

2 回答

  • -3

    UNIX很长一段时间是在PDP-11上开发的,这是一台来自DEC的16位计算机,它具有相当简单的指令集 . 几乎每条指令都有两个操作数,每个操作数可以有以下八种寻址模式之一,这里用MACRO 16汇编语言显示:

    0n  Rn        register
    1n  (Rn)      deferred
    2n  (Rn)+     autoincrement
    3n  @(Rn)+    autoincrement deferred
    4n  -(Rn)     autodecrement
    5n  @-(Rn)    autodecrement deferred
    6n  X(Rn)     index
    7n  @X(Rn)    index deferred
    

    可以通过在程序计数器R7上巧妙地重复使用某些寻址模式来编码中间地址和直接地址:

    27  #imm      immediate
    37  @#imm     absolute
    67  addr      relative
    77  @addr     relative deferred
    

    由于UNIX tty驱动程序使用 @# 作为控制字符, $ 替换为 #* 替换为 @ .

    PDP11指令字中的第一个操作数是指源操作数,而第二个操作数是指目的地 . 这反映在汇编语言的操作数顺序中,即源,然后是目标 . 例如,操作码

    011273
    

    指的是指令

    mov (R2),R3
    

    它将 R2 指向的单词移动到 R3 .

    此语法适用于8086 CPU及其寻址模式:

    mr0 X(bx,si)  bx + si indexed
    mr1 X(bx,di)  bx + di indexed
    mr2 X(bp,si)  bp + si indexed
    mr3 X(bp,di)  bp + di indexed
    mr4 X(si)     si indexed
    mr5 X(di)     di indexed
    mr6 X(bp)     bp indexed
    mr7 X(bx)     bx indexed
    3rR R         register
    0r6 addr      direct
    

    如果没有索引, m 为0,如果有一个字节的索引,则 m 为1;如果有一个双字节索引, m 为2,如果不是内存操作数, m 为3,则使用寄存器 . 如果存在两个操作数,则另一个操作数始终是寄存器并以 r 数字编码 . 否则, r 编码操作码的另外三位 .

    在该寻址方案中不可能使用中间体,所有采用立即数的指令都在其操作码中编码该事实 . 就像PDP-11语法一样,Immediates拼写 $imm .

    虽然英特尔总是为其汇编程序使用 dst, src 操作数排序,但没有特别令人信服的理由来修改此约定,并且编写UNIX汇编程序以使用PDP11中已知的 src, dst 操作数排序 .

    他们在实现8087浮点指令时与这种排序有一些不一致,可能是因为英特尔给出了非交换浮点指令的两个可能方向,这些指令与AT&T语法使用的操作数排序不匹配 .

    PDP11指令 jmp (跳转)和 jsr (跳转到子程序)跳转到其操作数的地址 . 因此, jmp foo 将跳转到 foo 并且 jmp *foo 将跳转到存储在变量 foo 中的地址,类似于 lea 在8086中的工作方式 .

    x86的 jmpcall 指令的语法被设计为好像这些指令在PDP11上工作一样,这就是为什么 jmp foo 跳转到 foojmp *foo 跳转到地址 foo 的值,即使8086实际上没有延迟寻址 . 这具有在语法上区分直接跳转和间接跳转的优点和便利,而不需要每个直接跳转目标的 $ 前缀,但逻辑上没有多少意义 .

    扩展语法以使用冒号指定段前缀:

    seg:addr
    

    当引入80386时,该方案使用四部分通用寻址模式适应其新的SIB寻址模式:

    disp(base,index,scale)
    

    其中 disp 是位移,base是基址寄存器, index 是索引寄存器, scale 是1,2,4或8,用于按索引寄存器中的一个来缩放索引寄存器 . 这等于Intel语法:

    [disp+base+index*scale]
    

    PDP-11的另一个显着特点是大多数指令都有字节和字变体 . 您使用哪一个由操作码的 bw 后缀表示,它直接切换操作码的第一位:

    010001   movw r0,r1
     110001   movb r0,r1
    

    这也适用于AT&T语法,因为大多数8086指令确实也可用于字节模式和字模式 . 后来80386和AMD K6引入了32位指令( long 后缀为 l )和64位指令(后缀为 q 为quad) .

    最后但并非最不重要的是,最初的惯例是使用下划线为C语言符号添加前缀(在Windows上仍然如此),因此您可以将名为 ax 的C函数与寄存器 ax 区分开来 . 当Unix系统实验室开发ELF二进制格式时,他们决定摆脱这种装饰 . 由于无法区分直接地址和寄存器,否则会在每个寄存器中添加 % 前缀:

    mov direct,%eax # move memory at direct to %eax
    

    这就是我们的方式今天的AT&T语法 .

  • 10

    汇编语言由汇编程序定义,汇编程序是解析汇编语言的软件 . 唯一的“标准”是机器代码,它必须与处理器匹配,但是如果您需要100个程序员并给它们机器代码标准(没有任何汇编语言提示),那么最终会有1到100种不同的汇编语言 . 对于处理器的所有用例(裸机,操作系统,应用程序工作),只要它们构成一个适合工具链的完整工具,它们都能很好地工作 .

    为了创建描述指令集的文档和汇编程序,您需要的第一个工具是指令集的创建者,机器代码的最佳利益 . 无论哪种方式无关紧要,它们都可以将其收缩或者内置,但是使用汇编程序,语法和机器代码文档,使用汇编程序的语法连接两者之间的点,将给任何人可能对该处理器感兴趣的一个起点 . 与英特尔和8086/88的情况一样 . 但这并不意味着masm和tasm与intels汇编程序完全兼容 . 即使每条指令的语法匹配,每条指令语法只是汇编语言的一部分,还有很多非指令类型的语法,指令,宏语言等等 . 而且那是来自DOS世界末日,有UNIX端,因此AT&T . gnu当时的人们是世界末日的unix,所以他们使用AT&T语法或衍生词是完全合理的,因为他们通常在端口期间搞乱汇编语言 . 也许有一个例外 .

    nasm和其他一些类似的尝试继续使用masm语法,因为masm是一个封闭的源代码Microsoft工具(如同那样,并且无论如何都是Borland C) . 这些可能是开源的,但是没有必要,更容易从头开始编写而不是尝试移植代码,我假设使用现代编译器构建,并且nasm已经存在 .

    问题就像问我为什么选择今天早上或任何特定日子选择的那双袜子 . 你的袜子可能对世界其他地方没有那么大的影响,但这个问题同样无关紧要和/或无法回答 . 答案可以部分归结为要求100位程序员为相同的机器代码定义制作汇编程序 . 这些程序员中的一些人可能对汇编语言有经验,并且可能选择在他们之前使用过的图像中创建汇编语言,这意味着他们中的一些将使一个看起来非常相似的汇编语言 . 但是他们之前使用的一个或多个可能是不同的,所以会有这些相似但仍然不同的群体 . 然后让我们说30年来问这100个人中的每一个人为什么问题...如果他们还活着......就像问我为什么你选择在30年前以你所做的方式写的程序中声明一个变量它 .

相关问题