ASM 只是 ML 的 MACRO,它有标准化指令吗?天然气呢?

Is ASM just a MACRO for ML, does it have standarized directives? What about GAS?

我参加了一些 MIPS 和 x86 汇编的课程。

对于 MIPS,我们使用了 MARS 模拟器。

对于 x86,我们将代码编写到模板化的 .S 文件中,他们基本上忽略了这些文件的细节,所以我们基本上编写了 body 子例程...

两人共享了一些关键字:

其他我们没有在 MARS 中使用的:

现在需要自学ARM,不知道如何开始编码。

我的理解是,在 MARS 中,我们编写的代码被编译为 ML 并直接发送到模拟 CPU 的内存,就好像它是一个微控制器(顺便说一句,我用微芯片做的图片)。然而,对于 x86,我们 运行 通过主机 OS,即 Linux,并且需要编译器添加“header”并将 VM 分配给程序,因此并不简单。

可能事实是他们教给我们的 ASM 更像是 ML 的 MACRO,而不是 作为 一种具有指令和特性的语言,这些指令和特性是低级的,需要被编译。

谷歌搜索我找到了 GAS,这可能是我们对 x86 所做的...

所以问题是:

你不需要搞得那么复杂

int main ( void )
{
    return(555);
}

gcc -O2 -c so.c -o so.o
objdump -D so.o

0000000000000000 <main>:
   0:   b8 2b 02 00 00          mov    [=10=]x22b,%eax
   5:   c3                      retq   

或者你可以看看生成的程序集,我更喜欢反汇编,所以现在我可以

.globl main
main:
    mov    [=11=]x22b,%eax
    retq

as so.s -o so.o
gcc so.o -o so
./so

当然什么也没有,但是

so.s

.globl fun
fun:
    mov    [=12=]x22b,%eax
    retq

so.c

#include <stdio.h>

int fun ( void );
int main ( void )
{
    printf("%u\n",fun());
    return(0);
}

as so.s -o fun.o
gcc so.c fun.o -o so
./so
555

当然,除此之外,您还可以根据需要将其复杂化。

gcc 输出 gnu 汇编器所以

int fun ( void )
{
    return(333);
}

gcc -O2 -save-temps -c so.c -o so.o
cat so.s
    .file   "so.c"
    .section    .text.unlikely,"ax",@progbits
.LCOLDB0:
    .text
.LHOTB0:
    .p2align 4,,15
    .globl  fun
    .type   fun, @function
fun:
.LFB0:
    .cfi_startproc
    movl    3, %eax
    ret
    .cfi_endproc
.LFE0:
    .size   fun, .-fun
    .section    .text.unlikely
.LCOLDE0:
    .text
.LHOTE0:
    .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609"
    .section    .note.GNU-stack,"",@progbits

虽然它们通常有过多的指令(​​对调试器和其他东西有用但并不总是 used/required),你可以利用这个事实在某种程度上帮助学习这个目标的 gnu 汇编器(x86 -64),但您当然需要处理器供应商(在本例中为 Intel)提供的文档。了解该文档中的语法不一定是您拥有或将使用的任何特定工具链使用的语法,您必须在那里 multi-lingual 但您会看到说明是什么,它们的作用及其限制等.

MARS 和其他类似环境对教学非常有用,并且通常出于这个原因而设计,避免了您可能掉入的许多陷阱。目标是通过玩模拟器来学习指令集,并熟悉汇编语言。我不喜欢汇编接口,出于教育目的,我认为学生应该 generate/see 机器代码,也许在那个 sim 中你可以,我只将它用于 SO 问题,我使用真实或模拟的 MIPS处理器,如果我想玩 MIPS。

汇编语言特定于工具而不是目标,假设任何目标的每个汇编器都有自己的汇编语言,如果碰巧有重叠,那就这样吧。

    global  fun
fun:
    mov    eax, 333
    ret

nasm so.s -felf64 -o so.o
gcc so.c so.o -o so
./so
333

有众所周知的 Intel 与 AT&T 之争,但这些不是语法,而是来自 Intel 标准的源目标交换。 nasm 不喜欢 .globl,尝试一下它喜欢不带点的 global。

    .globl  fun
fun:
    movl    %eax, 3
    ret

so.s:1: error: attempt to define a local label before any non-local labels
so.s:1: error: parser: instruction expected
so.s:3: error: parser: instruction expected

    globl  fun
fun:
    movl    %eax, 3
    ret

nasm so.s -felf64 -o so.o
so.s:1: error: parser: instruction expected
so.s:3: error: parser: instruction expected

    globl  fun <-- note this is line 1
fun:
    mov    %eax, 3 <--- this is line 3
    ret

nasm so.s -felf64 -o so.o
so.s:1: error: parser: instruction expected
so.s:3: error: expression syntax error


    globl  fun
fun:
    mov    eax, 333
    ret

nasm so.s -felf64 -o so.o
so.s:1: error: parser: instruction expected

    global  fun
fun:
    mov    eax, 333
    ret

而且nasm很开心

as so.s -o so.o

so.s: Assembler messages:
so.s:1: Error: no such instruction: `global fun'
so.s:3: Error: too many memory references for `mov'

    .global  fun
fun:
    mov    333, eax
    ret

so.s: Assembler messages:
so.s:3: Error: too many memory references for `mov'

    .global  fun
fun:
    mov    3, eax
    ret

so.s: Assembler messages:
so.s:3: Error: no instruction mnemonic suffix given and no register operands; can't size instruction

    .global  fun
fun:
    movl    3, eax
    ret

很高兴但是,这被打破了它认为 eax 是一个稍后要填写的标签

0000000000000000 <fun>:
   0:   c7 04 25 00 00 00 00    movl   [=18=]x14d,0x0
   7:   4d 01 00 00 
   b:   c3                      retq 

    .global  fun
fun:
    movl    3, %eax
    ret

0000000000000000 <fun>:
   0:   b8 4d 01 00 00          mov    [=18=]x14d,%eax
   5:   c3                      retq  

    .global  fun
fun:
    movl    3, %eax
    retq

0000000000000000 <fun>:
   0:   b8 4d 01 00 00          mov    [=18=]x14d,%eax
   5:   c3                      retq 

    .global  fun
fun:
    mov    3, %eax
    retq

0000000000000000 <fun>:
   0:   b8 4d 01 00 00          mov    [=18=]x14d,%eax
   5:   c3                      retq 

nasm:

    global  fun
fun:
    mov    eax, 333
    ret

0000000000000000 <fun>:
   0:   b8 4d 01 00 00          mov    [=19=]x14d,%eax
   5:   c3                      retq 

相同的机器代码,不同的汇编语言,不仅仅是颠倒源和目标(我使用 objdump 进行反汇编,所以这就是你看到该语法的原因)。

gas 采用 .globl 或 .global。由于 eax 寄存器是 32 位,因此 mov 的大小很明显,因此不需要后缀 movl 或 mov 显然可以与我拥有的 binutils 一起使用。同样,ret vs retq 产生了相同的指令。

汇编语言的乐趣,尤其是对于像 x86 这样痛苦的目标(你想学习的最后一个指令集,还有更多 useful/better 个指令集)。

但是您可以看到,汇编语言 can/does 对于相同的目标和相同的指令,根据所使用的工具而有所不同。像 MARS 这样的东西开始对这个用例更有意义。

学习 gcc/binutils (gnu) 工具不会出错,因为您可以在 Windows、Mac、Linux、BSD 等上使用它们,并且除了系统调用和可能的二进制文件格式之外,所有内容都将是相同的体验(好的链接器脚本,OS 具体内容会有所不同)。

根据目标,可能还有其他不错的选择。 nasm 对于那些从过去学习英特尔语法的人来说很受欢迎,我想其他人,以及可能已经放置了一段时间的代码可能会让你吐出一半的机会 nasm.

并且一个或另一个或两者都有用于 Intel 与 ATT source/destination 交换的命令行选项。