【问题标题】:Assembly what are data, .main and arr?汇编什么是数据、.main 和 arr?
【发布时间】:2020-11-16 15:31:06
【问题描述】:

今天我学习了汇编语言和许多指令,比如 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 语言

【问题讨论】:

  • 你的汇编教程应该在后面的章节中解释这一点。暂时不用太担心。
  • 文件中的所有内容都是汇编语言的一部分。请注意,汇编语言特定于工具而不是目标(特定的汇编器,例如 gnu 汇编器,而不是目标 risc-v/rv32)
  • @fuz 教程到此结束,它的目标是教基础知识,你能给我大致的想法吗?
  • arr:n: 这样的东西是标签。这些为程序中的位置命名。 .data.text 是在 datatext 部分 之间切换的指令。如果您的教程到此结束,那么它是非常不足的,因为这是非常重要的基础知识。考虑关注不同的书或购买一本关于汇编编程的书。如果你在 RISC-V 上没有找到任何东西,学习不同的架构然后切换到 RISC-V 可能是个好主意。
  • 这能回答你的问题吗? Assembler has:

标签: assembly riscv riscv32


【解决方案1】:

是的,所有这些都是汇编语言。请注意,汇编语言是由工具而不是目标定义的。因此 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创建的。反正。传统上,无论出于何种原因,您都可以使用 Google 搜索。代码(基本上是指令)位于名为 .text 的段中。预初始化数据为.data,未初始化数据为.bss。嗯gnu用了名字前面的点,文字,数据,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,这对我来说是今天的新名称,但无论哪种方式,我都只是查看对象并匹配链接描述文件中的内容,然后控制它们的去向。

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

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

【讨论】:

  • 请注意这里的拼写,尤其是包含撇号的单词。以下是一些正确的拼写,以及您帖子历史记录中的拼写错误数量:don't (765)、dos not (487)、can't (304)、won't (217)、let's (161)、is 't (147)。这里对不以英语为第一语言的人有一定的容忍度,但文体和故意拼写错误与网站的目标背道而驰,并且是为志愿编辑特意做的大量工作。请使用浏览器中的拼写检查功能。
  • @halfer 里面有一个不习惯,我一直在检查,如果您愿意,我可以停止检查并返回旧方式。您不必编辑这些答案,我担心您可能会改变某些陈述的含义。我将不得不回去审查所有内容。有时需要花费数小时来写下这些答案……才能理解确切的含义。如果生活就是这样,我宁愿删除它们。
  • 一般的 Stack Overflow 读者会认识到您在帖子中提供了很多价值,总的来说,您更愿意接受一个合理的请求。你在另一篇文章中给出了一个非常好的解决方案,并要求我展示它:根本不要使用收缩。不想正确拼写收缩有点奇怪,但我可以采用解决方案。
  • 我很明显没有改变任何东西的意思——这是一个虚假的指控。我建议你在 Meta Stack Overflow 上发帖询问是否可以出于文体原因拼写错误(我写这样的帖子肯定没有意义,因为我想我已经知道答案会是什么了是)。
  • 正如在其他地方指出的那样,摆脱撇号一直是很长一段时间的主题。这就是我被教导的方式,并且非常喜欢它,看起来更好,读起来更好,等等。其他拼写错误不是故意的。过去,我曾让人们通过尝试纠正语法等来弄乱我的技术文档。这周一直在查看我的答案,并寻找和修复不注意事项等......你发现我错过了一个,但不是我修复了许多其他内容,让您满意。
猜你喜欢
  • 2012-02-13
  • 2020-07-10
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
  • 2021-09-16
  • 2011-07-26
  • 1970-01-01
  • 2012-03-04
相关资源
最近更新 更多