assembly 汇编程序拇指模式

xggvc2p6  于 2023-04-21  发布在  其他
关注(0)|答案(2)|浏览(175)

我是用汇编程序编码的新手,我有一个关于.thumb和.Syntax统一指令的问题。我知道有一个指令集“Thumb”,它包含16位命令,Thumb2集包含16位和32位命令,ARM指令集也是如此。但我不明白这两个命令的开关。谢谢
我试着用不同的.thumb和.syntax的变体来编译我的代码,但我不能识别任何差异。

dxxyhpgq

dxxyhpgq1#

我试着用不同的.thumb和.syntax的变体来编译我的代码,但我不能识别任何差异。
应该没有区别;这是意料之中的。ARM汇编程序在某种程度上是独特的,因为助记符可以Map到不同的二进制值。
考虑一个用于实用函数的汇编程序'library'。它可以用'unified'编写,然后您的.thumb调用者可以使用该代码。汇编程序选项将确定'unified' library应该产生thumb二进制输出。希望您能看到它的价值。
所以.thumb说你只会生成Thumb代码。.syntax unified正在编写可以以EITHER二进制为目标的汇编程序。无论是传统的32位还是Thumb。对于后来的'thumb 2'集,有几乎100%的操作码对应。初始的'thumb 1'只允许访问寄存器R 0-R7,并且有很多限制。很难写'unified'这些CPU上的代码。
对于现代的Cortex-A CPU,您可以编写在任何一种模式下工作的汇编程序。如果您需要支持不理解Thumb的ARMv 4 CPU,它可能会很有用。对于较新的Cortex-A,thumb 2是一种更好的二进制编码。更好的代码密度和性能。对于ARMv 5(thumb 1)CPU,情况并非如此。对于ARMv 6,它处于中间位置,thumb通常更好。

jckbn6z7

jckbn6z72#

首先,汇编语言是汇编程序专用的,arms汇编语言的各种工具与gnu和clang以及其他工具不兼容,即使它是用于完全相同的arm核心和指令集。你不能笼统地谈论任何指令集汇编语言,因为这就是汇编语言的方式。语法统一指令意味着你正在谈论gnu汇编程序,gcc汇编程序或clang(llvm)(三种不同的汇编语言,有一些重叠)。
当arm代表acorn risc机器时,他们制造的是实际的芯片而不是ip。你有arm 1,arm 2和arm 3,其中一个或3的版本是2a或其他东西,你可以查一下,当它成为一家IP公司,它代表高级RISC机器时,你有了ARM 7产品名称和ARMV 4 T架构名称,拇指就诞生了。我在印刷的白色和蓝色封面的书中,拇指指令包括(有错别字)等效的手臂指令。当时每个拇指指令都有直接的手臂等效。(显然不是反之亦然)。
Thumb指令都是16位,thumb 2扩展是先前未定义的thumb指令,其被解码,然后附加的16位被解码。因此,将thumb或thumb+ thumb 2视为可变长度指令集而不是16或32更合适。您可以选择如何看待它以及如何避免与“全尺寸”arm指令混淆注意,最初bl和blx是两个独立的16位指令,它们不必彼此跟随,后来随着cortex-ms,定义改变,因此它们是thumb 2,如果你愿意的话,这不是以前未定义的(所有thumbvariant)指令。
所以armv 4 t thumb指令,最初是“所有thumb变体”版本,一些版本的架构参考手册会使用这个术语。
可能是一些文档失误,但arm似乎有几个不同的thumb指令集,至少有七个或更多,我怀疑这只是意味着例如armv 4 t和armv 5 t之间的差异,例如pop可以用来改变模式,在armv 4 t中只有bx和blx。
统一语法从一开始就令人困惑和糟糕,但如果你刚开始使用arm汇编语言(而不是64位),那么你可能会遇到它,因为你会发现大多数人使用它,例如gcc输出统一语法而不是预统一语法。
thumb文档显示了例如

ADD <Rd>, #<immed_8>

这是正确的thumb语法(好吧...汇编程序选择他们的语法,他们不必遵循其他语言,也不必遵循与其他汇编语言绑定的文档)。
等效臂指令为。

ADDS <Rd>, <Rd>, #<immed_8>

这两个机器码都列在文档的缩略图部分。
如果你

adds r0,#1

add r0,r0,#1

在Thumb模式中,您将得到一个语法错误(正如人们所希望的那样)。
Thumb 2扩展已经很多年了,arm仍然是一个也跑,虽然有了这个和接下来的几个核心,他们成为主宰处理器世界(你的x86盒子里有更多的非x86处理器比x86处理器,许多手臂和一些8051和/或z 80,x86是一个也跑)。
从我们的Angular 来看,至少在早期的armv-8 m之前,基本上有三种,但如果不是现在,它可能会改变。
所有拇指变体说明,得到rev E版本的手臂手臂,厚白色封面书在打印/纸(最后的打印书籍)和第一个pdf版本的手臂手臂。
cortex-m0附带的armv 6-m,它增加了几十个thumb 2扩展,以前是未定义的指令,现在是两个半字指令(如果必须的话,是32位)。
armv7-m从cortex-m3开始,在armv 6-m的基础上增加了100-150个新的thumb 2扩展。
由于某种原因,gas(gnu汇编程序)中的非UAL thumb指令集仍然存在,并且工作得很好,我有几十年前的代码。
该(有缺陷的)概念是,你可以使用arm of the day和thumb of the day之间的统一语法编写汇编语言代码。由于有大量的arm指令在thumb中没有等价物,这是没有意义的,唯一有点意义的是,如果你把自己限制在拇指指令,然后根据模式,它会使拇指指令或手臂相当。你无法编写有效的统一语言代码,因为你必须知道你在为哪个指令集编写代码,这是我们在统一语法之前和统一语法之后所做的事情,所以重点是什么?两个独立的指令集,两个独立的汇编语言,只需要为正确的一个写代码。这仍然是你今天必须做的。
一个副作用是你现在可以

add r0,r0,#1

在gas的非UAL语法中。因为它在功能上是相同的,所以你得到相同的指令。

add r0,r1,r2
add r0,r0,#1
.thumb
add r0,r1,r2
add r0,#1
add r0,r0,#1

给予

0:   e0810002    add r0, r1, r2
   4:   e2800001    add r0, r0, #1
   8:   1888        adds    r0, r1, r2
   a:   3001        adds    r0, #1
   c:   3001        adds    r0, #1

请注意,正如arm所记录的(gas的人往往不总是遵循ip/芯片供应商记录的汇编语言,但在这种情况下......)添加r 0,#1,有趣的是,反汇编人员将其显示为添加r 0,#1。
这些都是UAL之前的非UAL的例子。
然后我们再加上ual。

add r0,r1,r2
add r0,r0,#1
.thumb
add r0,r1,r2
add r0,#1
add r0,r0,#1
.syntax unified
add r0,r1,r2
adds r0,r1,r2

Disassembly of section .text:

00000000 <.text>:
   0:   e0810002    add r0, r1, r2
   4:   e2800001    add r0, r0, #1
   8:   1888        adds    r0, r1, r2
   a:   3001        adds    r0, #1
   c:   3001        adds    r0, #1
   e:   eb01 0002   add.w   r0, r1, r2
  12:   1888        adds    r0, r1, r2

现在add r 0,r1,r2是一个有效的thumb 2指令,它是许多armv7-m thumb 2扩展的一部分。这是编码,尽管它看起来有点像arm编码。这不是arm文档中的语法,arm文档中的thumb 2指令的语法是add.w
当然,如果你在armv 6期间添加此指令之前为非cortex-m编写。你现在有麻烦了。一条在处理器上无法工作的指令。我正在使用apt-gotten工具,并且可能会找出默认处理器,因为我没有指定一个。这是一个好主意:

.cpu cortex-m0
add r0,r1,r2
add r0,r0,#1
.thumb
add r0,r1,r2
add r0,#1
add r0,r0,#1
.syntax unified
add r0,r1,r2
adds r0,r1,r2

我们得到

arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:3: Error: attempt to use an ARM instruction on a Thumb-only processor -- `add r0,r1,r2'
so.s:4: Error: attempt to use an ARM instruction on a Thumb-only processor -- `add r0,r0,#1'
so.s:10: Error: cannot honor width suffix -- `add r0,r1,r2'

那个核心没有ARM指令

.cpu cortex-m0
.thumb
add r0,r1,r2
.syntax unified
add r0,r1,r2
adds r0,r1,r2

给予

arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:6: Error: cannot honor width suffix -- `add r0,r1,r2'

现在同一个工具将其视为thumb指令。这不是通常的,而是不同的,不兼容的汇编语言的一个例子,即使在同一个工具内。汇编语言之间针对相同目标的大多数差异是指令和其他微妙的东西,标签,注解,移植到gnu汇编程序的人似乎有意使gnu汇编程序与供应商自己的工具或文档汇编语言不兼容,msr mrs的指示在那里有一段时间相当痛苦。
所以让我们试试

.cpu cortex-m3
.thumb
add r0,r1,r2
.syntax unified
add r0,r1,r2
adds r0,r1,r2

它对此很满意

Disassembly of section .text:

00000000 <.text>:
   0:   1888        adds    r0, r1, r2
   2:   eb01 0002   add.w   r0, r1, r2
   6:   1888        adds    r0, r1, r2

但让我们更正确。

.cpu cortex-m3
.thumb
add r0,r1,r2
.syntax unified
add.w r0,r1,r2
adds.w r0,r1,r2
adds r0,r1,r2

Disassembly of section .text:

00000000 <.text>:
   0:   1888        adds    r0, r1, r2
   2:   eb01 0002   add.w   r0, r1, r2
   6:   eb11 0002   adds.w  r0, r1, r2
   a:   1888        adds    r0, r1, r2

这一切都很好。
正如上面的注解所指出的,.thumb告诉解析器下面的指令是thumb模式指令。

.cpu cortex-m3
add r0,r1,r2
.syntax unified
add.w r0,r1,r2
adds.w r0,r1,r2
adds r0,r1,r2

arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:3: Error: attempt to use an ARM instruction on a Thumb-only processor -- `add r0,r1,r2'
so.s:5: Error: attempt to use an ARM instruction on a Thumb-only processor -- `add.w r0,r1,r2'
so.s:6: Error: attempt to use an ARM instruction on a Thumb-only processor -- `adds.w r0,r1,r2'
so.s:7: Error: attempt to use an ARM instruction on a Thumb-only processor -- `adds r0,r1,r2'

gnu汇编解析器以.arm模式启动。所以你不必指定它,它是隐含的。
你可以按照上面评论中的回答来回走。

add r0,r1,r2
.thumb
add r0,r1,r2
.arm
add r0,r1,r2

00000000 <.text>:
   0:   e0810002    add r0, r1, r2
   4:   1888        adds    r0, r1, r2
   6:   0000        .short  0x0000
   8:   e0810002    add r0, r1, r2

(需要填充来对齐arm指令,自然这是完全损坏的代码,无法执行,它只是演示指令)。

.syntax unified
add r0,r1,r2
.thumb
add r0,r1,r2
.arm
add r0,r1,r2

.syntax unified表示后面的代码(在任一模式下)现在使用UAL汇编语言与非UAL汇编语言。

.thumb
add r0,r1,r2
.syntax unified
add r0,r1,r2
.syntax divided
add r0,r1,r2

给予

Disassembly of section .text:

00000000 <.text>:
   0:   1888        adds    r0, r1, r2
   2:   eb01 0002   add.w   r0, r1, r2
   6:   1888        adds    r0, r1, r2

gnu汇编程序从.syntax divided开始,就像我们到目前为止已经看到的那样。所以你从.arm .syntax divided开始,默认情况下,如果你想改变其中的任何一个,你必须使用指令,然后直到你使用另一个指令来改变模式或语法,它仍然通过文件。
很明显(如上所述),如果你想同时使用.thumb和.syntax,你可以将它们以任何一种顺序作为一对,让文件的其余部分使用该语言,gnu汇编程序thumb统一语法。
添加指令原来是工作的第一次,但也有其他拇指指令,这是相当痛苦的,让他们不使用thumb 2版本的工具将坚持在较大的版本代替。
在这种情况下,它工作得很干净。

.cpu cortex-m3
.thumb
.syntax unified
add r0,r1,r2
adds r0,r1,r2
adds.w r0,r1,r2
adds.n r0,r1,r2


.cpu cortex-m0
.thumb
.syntax unified
add r0,r1,r2
adds r0,r1,r2
adds.w r0,r1,r2
adds.n r0,r1,r2

信息有点混乱

so.s: Assembler messages:
so.s:5: Error: cannot honor width suffix -- `add r0,r1,r2'
so.s:7: Error: selected processor does not support `adds.w r0,r1,r2' in Thumb-2 mode

.cpu cortex-m0
.thumb
.syntax unified
add.w r0,r1,r2
adds r0,r1,r2
adds.w r0,r1,r2
adds.n r0,r1,r2

现在更好的消息

so.s: Assembler messages:
so.s:5: Error: selected processor does not support `add.w r0,r1,r2' in Thumb-2 mode
so.s:7: Error: selected processor does not support `adds.w r0,r1,r2' in Thumb-2 mode

如果你使用的是arm汇编语言(risc-v是另一种),你真的需要经常反汇编和检查,甚至在编译时也要确保它生成的代码可以运行,这也意味着你知道你有什么核心,什么代码可以运行,什么代码不可以运行。

如果你刚开始使用arm汇编语言和gnu汇编器,首先使用gnu汇编器(arm-whatever-as)而不是gcc。学习真实的的汇编语言,而不是内联的C汇编语言,这是另一种语言。然后学习翻译,如果你能绝对证明使用内联摆在首位(罕见).坚持使用统一语法,只要把.syntax unified放在前面从arm或thumb开始就以那种模式获得工具。要明白gnu汇编程序不是arms汇编程序,即使有时一个arm员工可能已经在上面工作过,它也是一个单独的汇编语言。它“倾向于”遵循arm文档,就语法而言,这条路走得比早期好得多。具体来说,我指的是指令语法,而不是语言的其他部分。假设arm文档是统一语法的。请始终获取ARM技术参考手册(ARM TRM)的内核(和版本!)始终获取您正在使用的内核的ARM架构参考手册(ARM ARM)(不存在必须在ARMV 5 T和ARMV 7A之间分离的全尺寸ARMV 6,并忽略了一大堆的armv 7a文档)。ARM程序员参考手册并不好。它们有暗示和不正确的陈述,导致非古鲁(甚至是ARM大师)陷入失败。有极其罕见的金块,如果信息在那里是任何使用,没有正确地记录在产品和架构文档中。您可能还希望获得您的核心的amba/axi文档或您的核心的-ish,它们有时有助于独占访问,以及您在某些内核中发现的不同总线。一般来说,总线文档是先进的,并为乡亲,有机会获得一个核心(工作在芯片上,有一个手臂核心在它)。
gnu汇编器的其他指令你需要知道你是在一个“全尺寸”的手臂上做多语言,还是在一个只有拇指的cortex-m上工作。
在gnu汇编程序中,标签以冒号结尾:对于标签的使用有一些规则。标签是工具为你计算的地址,所以你不必这样做。使用gnu汇编程序,标签默认为非函数标签。如果你保持相同的模式,你会更安全一些,但是如果你正在编写混合模式代码,您需要使用另一组指令来告诉工具,一些标签是函数,而一些是非函数地址(数据或相同模式分支目的地)。

.syntax unified
.arm
here:
    bl one
    bl two
    b .
one:
    bx lr
three:
    bx lr
.thumb
.align
two:    
    bl three
    bx lr

给出(链接)

Disassembly of section .text:

00008000 <here>:
    8000:   eb000001    bl  800c <one>
    8004:   eb000002    bl  8014 <two>
    8008:   eafffffe    b   8008 <here+0x8>

0000800c <one>:
    800c:   e12fff1e    bx  lr

00008010 <three>:
    8010:   e12fff1e    bx  lr

00008014 <two>:
    8014:   f7ff fffc   bl  8010 <three>
    8018:   4770        bx  lr

这是各种各样的坏了。你不能从手臂到拇指流血。而且工具没有警告也没有错误。

.syntax unified
.arm
here:
    bl one
    bl two
    b .
one:
    bx lr
three:
    bx lr
.thumb
.align
.thumb_func
two:    
    bl three
    bx lr

现在我并不期望工具能做到这一点,但gnu工具(我认为在一些主要版本之后)会为你做到这一点:

Disassembly of section .text:

00008000 <here>:
    8000:   eb000001    bl  800c <one>
    8004:   eb000005    bl  8020 <__two_from_arm>
    8008:   eafffffe    b   8008 <here+0x8>

0000800c <one>:
    800c:   e12fff1e    bx  lr

00008010 <three>:
    8010:   e12fff1e    bx  lr

00008014 <two>:
    8014:   f7ff fffc   bl  8010 <three>
    8018:   4770        bx  lr
    801a:   46c0        nop         ; (mov r8, r8)
    801c:   0000        movs    r0, r0
    ...

00008020 <__two_from_arm>:
    8020:   e59fc000    ldr ip, [pc]    ; 8028 <__two_from_arm+0x8>
    8024:   e12fff1c    bx  ip
    8028:   00008015    .word   0x00008015
    802c:   00000000    .word   0x00000000

所以这将它固定在一个方向上,而不是另一个方向。从手臂到拇指。.thumb_func表示下一个标签是一个函数(是的,有很多额外的语法你可以使用周围的更高级别的语言概念的函数或过程,等等。至少它归结为这一点)。所以它是位置的,你不必把它放在前面的一行,你可以在里面放其他东西,而不是标签。
没有.arm_func

.syntax unified
.arm
.type here,%function
.type one,%function
.type three,%function
here:
    bl one
    bl two
    b .
one:
    bx lr
three:
    bx lr
.thumb
.align
.thumb_func
two:    
    bl three
    bx lr

.type... %函数。由于标签名称在指令中,因此您不必将其放在标签前面。
.type也适用于thumb,甚至不必在.thumb区域内

.syntax unified
.arm
.type here,%function
.type one,%function
.type three,%function
.type two,%function
here:
    bl one
    bl two
    b .
one:
    bx lr
three:
    bx lr
.thumb
.align
two:    
    bl three
    bx lr

并且尽管该代码不是真正可用的,但至少它不会由于在没有正确切换模式的情况下切换指令集而崩溃。

Disassembly of section .text:

00008000 <here>:
    8000:   eb000001    bl  800c <one>
    8004:   eb000005    bl  8020 <__two_from_arm>
    8008:   eafffffe    b   8008 <here+0x8>

0000800c <one>:
    800c:   e12fff1e    bx  lr

00008010 <three>:
    8010:   e12fff1e    bx  lr

00008014 <two>:
    8014:   f000 f80a   bl  802c <__three_from_thumb>
    8018:   4770        bx  lr
    801a:   46c0        nop         ; (mov r8, r8)
    801c:   0000        movs    r0, r0
    ...

00008020 <__two_from_arm>:
    8020:   e59fc000    ldr ip, [pc]    ; 8028 <__two_from_arm+0x8>
    8024:   e12fff1c    bx  ip
    8028:   00008015    .word   0x00008015

0000802c <__three_from_thumb>:
    802c:   4778        bx  pc
    802e:   e7fd        b.n 802c <__three_from_thumb>
    8030:   eafffff6    b   8010 <three>
    8034:   00000000    andeq   r0, r0, r0

哦,所以gnu linker添加了这些trampolines(它们使用另一个名字)来为你切换模式。你必须链接才能看到它们。我假设旧版本的工具和/或其他工具链,它们有自己的语法来声明这些声明,如果你在错误的指令集区域中bl到标签,可能会给予警告。
至少在当前版本中,你会看到gcc会为thumb函数标签生成.type和.thumb_func。
如果你在一个cortex-m上工作,大部分情况下你不需要将标签声明为函数,因为没有模式开关,但是向量表需要thumb函数地址(函数的地址ORRed与1。如果你认为加1,你会遇到麻烦)。

.cpu cortex-m0
.syntax unified
.thumb
.word 0x20000800
.word reset

.align
reset:
    b .

Disassembly of section .text:

00000000 <reset-0x8>:
   0:   20000800    .word   0x20000800
   4:   00000008    .word   0x00000008

00000008 <reset>:
   8:   e7fe        b.n 8 <reset>

现在这是错误的,将不会 Boot 。向量表需要lsbit设置每个文档。
由于某些原因,即使文档暗示它应该工作,这个黑客也不起作用。

.cpu cortex-m0
.syntax unified
.thumb
.word 0x20000800
.word reset|1

.align
reset:
    b .

so.s: Assembler messages:
so.s:6: Error: invalid operands (.text and *ABS* sections) for `|'

所以有时候你会看到这种可怕的黑客

.cpu cortex-m0
.syntax unified
.thumb
.word 0x20000800
.word reset+1

.align
reset:
    b .

Disassembly of section .text:

00000000 <reset-0x8>:
   0:   20000800    .word   0x20000800
   4:   00000009    .word   0x00000009

00000008 <reset>:
   8:   e7fe        b.n 8 <reset>

只要做好就行了

.cpu cortex-m0
.syntax unified
.thumb
.word 0x20000800
.word reset

.align
.thumb_func
reset:
    b .

Disassembly of section .text:

00000000 <reset-0x8>:
   0:   20000800    .word   0x20000800
   4:   00000009    .word   0x00000009

00000008 <reset>:
   8:   e7fe        b.n 8 <reset>

(yes如果你同时做这两件事,这个工具实际上是在救你自己)。
注意,你使用的特定gnu汇编器或gcc二进制文件本身就是用某些规范构建的程序。你可以将它们构建为默认的armv 4 t或arm 7a或其他。如果你没有指出核心,那么它就使用默认值(你可以构建一个gnu汇编器,它会打破上面的例子,给出与我使用的相同的结果)。
简而言之,正如上面的评论中已经回答的那样。

gnu汇编程序在arm模式下启动,使用分割语法。这意味着使用arm指令集构建以下指令,使用非统一语法(直到其他指令另有说明)
.thumb指示此指令之后的代码将使用thumb指令集构建(直到其他指令……)
.syntax unified意味着要使用此工具版本的统一语法来解析下面的代码。
.arm表示遵循此指令的代码将使用arm指令集构建
.syntax divided意味着将使用针对每种模式的特定语法的此工具版本来解析随后的代码。
.syntax unified/divided适用于后面的.arm和.thumb指令。您可能希望将.syntax unified放在每个文件的顶部。
Thumb多于ARM“指令集”是一个棘手的问题,如上面所指出的。但是这些指令与指定的目标核心/处理器相结合,定义该目标所支持的arm和/或thumb指令。arm模式随着时间的推移添加了一些新的指令,但不像thumb full sized或cortex-m,它们看到了大量的添加。需要指定正确的核心或较小的核心,该核心具有完全受您正在使用的核心支持的子集(例如armv 4 t或armv 6-m/cortex-m0)。
你说你看不出区别。

add r0,r1,r2
.thumb
add r0,r1,r2
.syntax unified
add r0,r1,r2

Disassembly of section .text:

00000000 <.text>:
   0:   e0810002    add r0, r1, r2
   4:   1888        adds    r0, r1, r2
   6:   eb01 0002   add.w   r0, r1, r2

同样语法的arm、thumb和thumb 2版本,但其中一个在功能上与另外两个不一样。

相关问题