汇编什么是数据,.main和arr



今天我学习了汇编语言和许多指令,比如J JAL BNE等等。。。但突然间,我看到了以下内容:

data
arr: .word 2, 4, 6, 8
n: .word 9
.text
main:   add     t0, x0, x0
             addi    t1, x0, 1
             la      t3, n
             lw      t3, 0(t3)
fib:       beq     t3, x0, finish
             add     t2, t1, t0
             mv      t0, t1
             mv      t1, t2
             addi    t3, t3, -1
             j       fib

请允许我举个例子,这些数据是什么,arr,n和.text?这些是汇编语言的一部分吗?为什么我们需要main?这不是C语言

是的,所有这些都是汇编语言。请注意,汇编语言是由工具定义的,而不是由目标定义的。因此,risc-v的gnu汇编程序(gas)可能与risc-v其他汇编程序不同。大多数不同之处在于其他东西,除了指令之外的东西,但有时指令也会从一个工具变为另一个工具。唯一不变的就是机器代码,如果汇编程序能够生成正确的指令,汇编语言就很容易看起来像这个
add banana, orange

但无论如何。

unsigned int fun ( unsigned int a, unsigned int b )
{
return(a+b+7);
}

我目前为这个目标使用的gcc编译器正在从该代码中生成这个。

.file   "so.c"
.option nopic
.attribute arch, "rv32i2p0_m2p0_a2p0_f2p0_d2p0_c2p0"
.attribute unaligned_access, 0
.attribute stack_align, 16
.text
.align  1
.globl  fun
.type   fun, @function
fun:
addi    a1,a1,7
add a0,a1,a0
ret
.size   fun, .-fun
.ident  "GCC: (GNU) 10.2.0"

这些东西中的一些是显而易见的,有些不是那么多,实际上很少有必要为这个目标和工具制作一个有用的对象

.globl  fun
fun:
addi    a1,a1,7
add a0,a1,a0
ret

fun:只是一个标签,意思是地址。当链接器将对象放在一起以生成一个可用的程序时,它会对标签进行排序,并根据需要将它们转换为固定地址或相对地址。这是一种节省劳动力的设备。否则

00000000 <skip-0x8>:
0:   c501                    beqz    x10,8 <skip>
2:   0001                    nop
4:   0001                    nop
6:   0001                    nop
00000008 <skip>:
8:   00c58533            add x10,x11,x12

00000000 <skip-0xc>:
0:   c511                    beqz    x10,c <skip>
2:   0001                    nop
4:   0001                    nop
6:   0001                    nop
8:   0001                    nop
a:   0001                    nop
0000000c <skip>:
c:   00c58533            add x10,x11,x12

指令的编码,你可以自己查找,基本上包括到目的地的距离,如果没有标签,我们必须自己计算指令的数量,在汇编语言中,不知何故,指示向前跳3个半单词,向后跳10个半单词。

Gnu汇编程序对此有一个语法。

nop
nop
nop
beqz x10,.+4
nop
nop
nop
nop
nop
nop

00000000 <.text>:
0:   0001                    nop
2:   0001                    nop
4:   0001                    nop
6:   c111                    beqz    x10,a <.text+0xa>
8:   0001                    nop
a:   0001                    nop
c:   0001                    nop
e:   0001                    nop
10:   0001                    nop
12:   0001                    nop

但你通常不想这样做,就好像你改变了分支指令和目标之间的指令/字节数一样——你必须不断调整一些/很多偏移量。

所以标签是地址,在gnu汇编程序中,它们以冒号结尾,不使用保留字。某些汇编语言不使用冒号。

细分市场:

int mybss;
int mydata=5;
int text ( void )
{
mybss=3;
return(++mydata);
}

Disassembly of section .text:
00000000 <text>:
0:   000007b7            lui x15,0x0
4:   0007a503            lw  x10,0(x15) # 0 <text>
8:   00000737            lui x14,0x0
c:   468d                    li  x13,3
e:   0505                    addi    x10,x10,1
10:   00d72023            sw  x13,0(x14) # 0 <text>
14:   00a7a023            sw  x10,0(x15)
18:   8082                    ret
Disassembly of section .sbss:
00000000 <mybss>:
0:   0000                    unimp
...
Disassembly of section .sdata:
00000000 <mydata>:
0:   0005                    c.nop   1
...

嗯,这很有趣,那是gnu-gcc创建的。无论如何传统上,无论出于什么原因,你都可以在谷歌上搜索。代码(基本上是指令)在一个名为.text的段中。预初始化的数据是.data,未初始化的数据为.bss。gnu在名称、text、data、bss前面使用了句点。

Gnu汇编程序有一些快捷方式

.text
nop
.data
.word 1,2,3

但是完整的语法是

.section .text
.section .data

我想,如果没有以某种方式保留,你可以随心所欲:

.section .hello
nop
add x11,x12,x13
j .
.word 0xA,0xBBBB
.section .world
mystuff: .word 1,2,3,4
Disassembly of section .hello:
00000000 <.hello>:
0:   0001                    nop
2:   00d605b3            add x11,x12,x13
6:   a001                    j   6 <.hello+0x6>
8:   000a                    c.slli  x0,0x2
a:   0000                    unimp
c:   0000bbbb            0xbbbb
Disassembly of section .world:
00000000 <mystuff>:
0:   0001                    nop
2:   0000                    unimp
4:   0002                    c.slli64    x0
6:   0000                    unimp
8:   00000003            lb  x0,0(x0) # 0 <mystuff>
c:   0004                    0x4
...

这些都是对象转储,请注意,对于从偏移量零开始的输出,每个段都有自己的数据块。还要注意,这是反汇编程序,因此它试图将数据反汇编为指令,这很令人困惑。

这里的想法是隔离这些不同的数据/信息类型,以便控制它们的去向。例如,在微控制器中,您可能在一个地址空间0x00000000有闪存,在另一个0x20000000有sram,因此您希望将只读代码和只读数据与读/写数据隔离开来,这样您就可以告诉链接器将东西放在哪里。

int mybss;
int mydata=5;
const int myrodata = 25;
int text ( void )
{
mybss=3;
return(++mydata);
}

您可以在链接器命令行上将点连接到链接器,也可以使用特定于工具、链接器而非目标通用的链接器脚本。与汇编语言一样,不希望代码逐字逐句地移植到其他工具链。

MEMORY
{
bob : ORIGIN = 0x00000000, LENGTH = 0x1000
ted : ORIGIN = 0x20000000, LENGTH = 0x1000
}
SECTIONS
{
.text   : { *(.text*)       } > bob
.rodata : { *(.srodata*)    } > bob
.data   : { *(.sdata*)      } > ted
.bss    : { *(.sbss*)       } > ted
}

显然不是一个实际可用的二进制文件,但工具不知道他们只是按照我的要求

Disassembly of section .text:
00000000 <text>:
0:   200007b7            lui x15,0x20000
4:   0007a503            lw  x10,0(x15) # 20000000 <mydata>
8:   20000737            lui x14,0x20000
c:   468d                    li  x13,3
e:   0505                    addi    x10,x10,1
10:   00d72223            sw  x13,4(x14) # 20000004 <mybss>
14:   00a7a023            sw  x10,0(x15)
18:   8082                    ret
Disassembly of section .rodata:
0000001c <myrodata>:
1c:   0019                    c.nop   6
...
Disassembly of section .data:
20000000 <mydata>:
20000000:   0005
...
Disassembly of section .bss:
20000004 <mybss>:
20000004:   0000
...

在我有bob和ted的地方,大多数人会用rom和ram或其他更有用的名字。在左边,我有.text和.data等,你也可以在那里制作东西,需要与读取这个二进制文件的工具相匹配,并寻找外部工具想要看到的某些关键词。但有了gnu链接器,你就可以弥补这些不足。中间的名称需要与对象中的名称匹配,所以我不知道为什么是.sdata而不是.data,这对我来说是一个新的名称,但无论哪种方式,我都只是查看对象并匹配链接器脚本中的内容,然后控制它们的去向。

最后一个主要内容:再一次是一个标签,你已经看到编译函数的函数名基本上是一个用标签表示的地址。该函数/子例程的入口点。您的C程序不进入main(),在二进制文件中有在main之前运行的引导程序代码,然后该代码调用main。当您使用gcc hello_world.c -o hello_world时,需要进行预处理、编译到程序集、组装到对象并使用默认链接器和C库引导程序进行链接,以生成特定于目标(操作系统)的二进制文件,这样您就可以运行它./hello_world

你遇到的代码可能是以这种方式链接和运行的(即使你发布的内容不起作用)。或者作者只是习惯于使用main这个词,就像我们这些编写C程序的人一样。即使是编译成汇编语言的C代码,就工具而言,它也只是另一个标签。C的引导程序将专门对其进行外部调用,因此当所有内容都被链接时,其中一个对象中需要有一个main(),但您可以在不使用名为main()的函数的情况下构建二进制文件,如果您掌握了这些工具,它就可以工作。至少对于gnu。由于某些原因,其他工具可能需要该函数名称。

相关内容

  • 没有找到相关文章

最新更新