(资源链接见文末)
RISC-V ISA介绍
加州伯克利所研发的第五代精简指令集。
ISA指令集架构:是底层硬件电路面向上层软件程序提供的一层接口规范。
ISA(处理器)的宽度指的是CPU中通用寄存器的宽度,这决定了寻址范围的大小,以及数据运算能力。
ISA的宽度与指令编码长度无关。
目前主流的移动智能终端,个人计算机和服务器用的寄存器是64位。
命名规范
RV[###][abc......xyz]
[###]表示的是寄存器的位宽,后面的字母标识处理器支持的指令集模块集合。
例如:RV31MA、RV64GC。
特点
RISC-V每条指令是32位。
RISC-V是模块化ISA。
增量式ISA:x86
模块化ISA:由1个基本整数指令集+多个可选的指令集组成。基础指令是固定的,永远不会改变。设计cpu的可以像插件一样去堆模块。
RISC-V ISA = 1个基本整数指令集 + 多个可选的扩展指令集
基本整数指令集:唯一强制要求实现的基础指令集,其他指令集都是可选的扩展模块。
基本指令集 | 描述 |
RV32I | 32位整数指令集 |
RV32E | RV32I的子集,用于小型的嵌入式场景 |
RV64I | 64位的整数指令集,兼容RV32I |
RV128I | 128位整数指令集,兼容RV64I和RV32I |
扩展模块指令集:RISC-V允许在视线中以可选的形式实现其他标准化和非标准化的指令集扩展。特定组合“IMAFD”被称为“通用”组合,用英文字母G表示。
扩展指令集 | 描述 |
M | 整式乘法与除法指令集 |
A | 存储器原子指令集 |
F | 单精度浮点指令集 |
D | 双精度浮点指令集 |
C | 压缩指令集 |
...... | 其它标准化和非标准化指令集 |
例子:RV32I:最基本的RISC-V实现;RV32IMAC:32位实现,支持I+M+A+C; RV64GC: 64位实现,支持IMAFDC。
HART
hart = hardware thread
英特尔提出的超线程概念,一个处理器处理多个指令流。买回来的处理器说是4核,实际上是两核,每个核可以同时执行两条指令流。
引入hart概念,一个hart就是一个虚拟的cpu。一个hart可以不受外界干扰的自主地去获取和执行risc-v指令。
特权级别
level | encoding | name | |
0 | 00 | user/application | U |
1 | 01 | supervisor | S |
2 | 10 | reserved | |
3 | 11 | machine | M |
当运行在用户态时,就是说cpu运行在user级别,进入到内核的时候就是supervisor级别。固件就是就是machine级别。运行在machine模式是不开虚拟地址的,全部运行在物理地址。
risc-v芯片一上电首先是进入到machine模式,再进入到supervisor模式,此时也叫保护模式,虚拟地址打开。
进程的实现依赖于虚拟地址,虚拟地址的实现需要MMU硬件支持。
Control and Status Register(CSR)
不同的特权级别下时分布对应各自的一套CSR,用于控制和获取响应level下的处理器工作状态。
高级别的特权可以访问低级别的CSR。比如说machine级别可以访问user级别的csr。
rsicv定义了专门用于操作csr的指令。
如果是用户程序,不太需要跟csr打交道。
内存管理与保护
物理内存保护(Physical Memory Protection,PMP):允许M模式指定U模式可以访问的内存地址;支持R/W/X(可执行),以及lock。
虚拟内存:需要支持supervisor level;用硬件MMU支持实现。
异常和中断
异常:主动触发,cpu给你一次改过自新的机会,去执行一段挽救程序;当执行到非法指令的时候,cpu会停掉此指令流跳到一个特殊的地址去执行一段特殊的程序(自己写的程序,想对异常做的处理),执行完之后回到之前的指令再次运行;比如说除0异常;
中断:被动触发;cpu停掉当前程序,跳转到执行中断处理程序,执行完返回到下一条指令去执行;比如说外设通知你发生一件什么事情,跑去执行别的指令,执行完再回到下条指令,就像中断没有发生过一样。
编译与链接
GCC(GNU Compiler Collection)
由GNU开发的,遵循GPL许可证发行的编译器套件;支持此c、c++、objective-c、fortran、ada和go语言等多种语言前端,已被移植到多种计算机体系架构上,如x86、arm、risc-v等;GCC的初衷是为GNU操作系统专门编写一款编译器,现以被大多数“unix-like”操作系统(如linux、BSD、MacOS)采纳为标准的编译器。
gcc [options][filenames]
常用选项 | 含义 |
-E | 只做预处理 |
-c | 值编译不链接,生成目标文件“-.o” |
-S | 生成汇编代码 |
-o file | 把输出生成到由file指定文件名的文件中 |
-g | 在输出的文件中加入支持调试的信息 |
-v | 显示输出详细的命令执行过程信息 |
gcc -E foo.c -o foo.i // preprocessor/cc1
gcc -S foo.i -o foo.s // compiler/cc1
gcc -c foo.s -o foo.o // assembler/as
gcc foo.o -o a.out // linker/ld
gcc的主要执行步骤:
编译(cc1,这里针对c语言,不同的语言由自己的编译器):编译完成“预处理”和“编译”。
汇编(as):汇编器将汇编语言代码转换成机器(cpu)可以执行的指令。
链接(ld):链接器将汇编器生成的目标文件和一些标准库(譬如libc)文件组合,形成最终可执行的应用程序。
gcc涉及的文件类型:
.c:C源文件
.cc/.cxx/.cpp:c++源文件
.i:经过预处理的c源文件
.s/.S:汇编语言源文件
.h:头(header)文件
.o:目标(object)文件
.a/.so:编译后的静态库(archive)文件和共享库(shared object)文件
a.out:可执行文件
ELF介绍
ELF(Executable Format)是一种unix-like系统上的二进制文件格式标准。
ELF标准中定义的采用ELF格式的文件分为4类:
ELF文件类型 | 说明 | 实例 |
可重定位文件(relocatable file) | 内容包含了代码和数据,可以被链接成可执行文件或共享目标文件 | linux上的.o文件 |
可执行文件 | 可以直接执行的文件 | linux上的a.out文件 |
共享目标文件 | 内容包含了代码和数据,可以作为链接器的输入,在链接阶段和其他的relacatable file或者shared object file一起链接成新的object file;或者在运行阶段,作为动态链接器的输入,和可执行文件结合,作为进程的一部分来运行。 | linux上的.so文件 |
核心转储文件(core dump file) | 进行意外终止时,系统可以将该进程的部分内容和终止时的其他状态信息保存到该文件中以供调试分析。 | linux上的core文件 |
ELF文件格式:
ELF Header | |
Program Header Table | 运行视图 |
.text | 程序指令 |
.init | 做初始化的一些指令 |
.data | 数据:全局变量等 |
.bss | |
...... | |
Section Header Table | 从链接角度去描述了这个文件的内容 |
.text和.init等这些信息放置的时候都会section(节)对齐,但是在运行的时候会合在一起以节省空间,于是有了segment(段)概念,segment的信息存放于program header table中。segment fault就是因为出错的时候在内存中失败。
ELF文件处理相关工具:
Binutils官网地址:https://www.gnu.org/software/binutils/
ar:归档文件,将多个文件打包成一个大文件。
as:被gcc调用,输入汇编文件,输出目标文件工链接器ld连接。
ld:gnu链接器,被gcc调用,它把目标文件和各种库文件结合在一起,重定位数据,并链接符号引用。
objcopy:执行文件格式转换。
objdump:显示ELF文件的信息。
readelf:显示更多ELF格式文件的信息(包括DWARF调试信息)
示例1:
gcc -c hello.c
readelf -h hello.o // 查看头信息
readelf -S hello.o // 查看section信息
readelf -SW hello.o
实例2:
gcc -g -c hello.c
objdump -S hello.o // 显示汇编指令
练习题
编写程序hello.c
#include <stdio.h>
int main() {
printf("hello world!\n");
return 0;
}
使用 gcc
进行本地编译生成目标文件 hello.o,-m64
是 gcc 编译器的一个选项,它指示编译器生成 64 位目标代码。
gcc -c -m64 hello.c
查看hello.h的头信息
$ readelf -h hello.o
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: DYN (Shared object file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x1060
Start of program headers: 64 (bytes into file)
Start of section headers: 14712 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 13
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 30
查看hello.o的section header elf
$ readelf -S hello.o
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .interp PROGBITS 0000000000000318 00000318
000000000000001c 0000000000000000 A 0 0 1
[ 2] .note.gnu.propert NOTE 0000000000000338 00000338
0000000000000020 0000000000000000 A 0 0 8
[ 3] .note.gnu.build-i NOTE 0000000000000358 00000358
0000000000000024 0000000000000000 A 0 0 4
[ 4] .note.ABI-tag NOTE 000000000000037c 0000037c
0000000000000020 0000000000000000 A 0 0 4
[ 5] .gnu.hash GNU_HASH 00000000000003a0 000003a0
0000000000000024 0000000000000000 A 6 0 8
[ 6] .dynsym DYNSYM 00000000000003c8 000003c8
00000000000000a8 0000000000000018 A 7 1 8
[ 7] .dynstr STRTAB 0000000000000470 00000470
0000000000000082 0000000000000000 A 0 0 1
[ 8] .gnu.version VERSYM 00000000000004f2 000004f2
000000000000000e 0000000000000002 A 6 0 2
[ 9] .gnu.version_r VERNEED 0000000000000500 00000500
0000000000000020 0000000000000000 A 7 1 8
[10] .rela.dyn RELA 0000000000000520 00000520
00000000000000c0 0000000000000018 A 6 0 8
[11] .rela.plt RELA 00000000000005e0 000005e0
0000000000000018 0000000000000018 AI 6 24 8
[12] .init PROGBITS 0000000000001000 00001000
000000000000001b 0000000000000000 AX 0 0 4
[13] .plt PROGBITS 0000000000001020 00001020
0000000000000020 0000000000000010 AX 0 0 16
[14] .plt.got PROGBITS 0000000000001040 00001040
0000000000000010 0000000000000010 AX 0 0 16
[15] .plt.sec PROGBITS 0000000000001050 00001050
0000000000000010 0000000000000010 AX 0 0 16
[16] .text PROGBITS 0000000000001060 00001060
0000000000000175 0000000000000000 AX 0 0 16
[17] .fini PROGBITS 00000000000011d8 000011d8
000000000000000d 0000000000000000 AX 0 0 4
[18] .rodata PROGBITS 0000000000002000 00002000
0000000000000011 0000000000000000 A 0 0 4
[19] .eh_frame_hdr PROGBITS 0000000000002014 00002014
0000000000000044 0000000000000000 A 0 0 4
[20] .eh_frame PROGBITS 0000000000002058 00002058
0000000000000108 0000000000000000 A 0 0 8
[21] .init_array INIT_ARRAY 0000000000003db8 00002db8
0000000000000008 0000000000000008 WA 0 0 8
[22] .fini_array FINI_ARRAY 0000000000003dc0 00002dc0
0000000000000008 0000000000000008 WA 0 0 8
[23] .dynamic DYNAMIC 0000000000003dc8 00002dc8
00000000000001f0 0000000000000010 WA 7 0 8
[24] .got PROGBITS 0000000000003fb8 00002fb8
0000000000000048 0000000000000008 WA 0 0 8
[25] .data PROGBITS 0000000000004000 00003000
0000000000000010 0000000000000000 WA 0 0 8
[26] .bss NOBITS 0000000000004010 00003010
0000000000000008 0000000000000000 WA 0 0 1
[27] .comment PROGBITS 0000000000000000 00003010
000000000000002b 0000000000000001 MS 0 0 1
[28] .symtab SYMTAB 0000000000000000 00003040
0000000000000618 0000000000000018 29 46 8
[29] .strtab STRTAB 0000000000000000 00003658
0000000000000203 0000000000000000 0 0 1
[30] .shstrtab STRTAB 0000000000000000 0000385b
000000000000011a 0000000000000000 0 0 1
对hello.o进行反汇编并查看c程序源码和机器指令的对应关系
$ objdump -d hello.o
hello: file format elf64-x86-64
Disassembly of section .init:
0000000000001000 <_init>:
1000: f3 0f 1e fa endbr64
1004: 48 83 ec 08 sub $0x8,%rsp
1008: 48 8b 05 d9 2f 00 00 mov 0x2fd9(%rip),%rax # 3fe8 <__gmon_start__>
100f: 48 85 c0 test %rax,%rax
1012: 74 02 je 1016 <_init+0x16>
1014: ff d0 callq *%rax
1016: 48 83 c4 08 add $0x8,%rsp
101a: c3 retq
Disassembly of section .plt:
0000000000001020 <.plt>:
1020: ff 35 9a 2f 00 00 pushq 0x2f9a(%rip) # 3fc0 <_GLOBAL_OFFSET_TABLE_+0x8>
1026: f2 ff 25 9b 2f 00 00 bnd jmpq *0x2f9b(%rip) # 3fc8 <_GLOBAL_OFFSET_TABLE_+0x10>
102d: 0f 1f 00 nopl (%rax)
1030: f3 0f 1e fa endbr64
1034: 68 00 00 00 00 pushq $0x0
1039: f2 e9 e1 ff ff ff bnd jmpq 1020 <.plt>
103f: 90 nop
Disassembly of section .plt.got:
0000000000001040 <__cxa_finalize@plt>:
1040: f3 0f 1e fa endbr64
1044: f2 ff 25 ad 2f 00 00 bnd jmpq *0x2fad(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
104b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Disassembly of section .plt.sec:
0000000000001050 <puts@plt>:
1050: f3 0f 1e fa endbr64
1054: f2 ff 25 75 2f 00 00 bnd jmpq *0x2f75(%rip) # 3fd0 <puts@GLIBC_2.2.5>
105b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
Disassembly of section .text:
0000000000001060 <_start>:
1060: f3 0f 1e fa endbr64
1064: 31 ed xor %ebp,%ebp
1066: 49 89 d1 mov %rdx,%r9
1069: 5e pop %rsi
106a: 48 89 e2 mov %rsp,%rdx
106d: 48 83 e4 f0 and $0xfffffffffffffff0,%rsp
1071: 50 push %rax
1072: 54 push %rsp
1073: 4c 8d 05 56 01 00 00 lea 0x156(%rip),%r8 # 11d0 <__libc_csu_fini>
107a: 48 8d 0d df 00 00 00 lea 0xdf(%rip),%rcx # 1160 <__libc_csu_init>
1081: 48 8d 3d c1 00 00 00 lea 0xc1(%rip),%rdi # 1149 <main>
1088: ff 15 52 2f 00 00 callq *0x2f52(%rip) # 3fe0 <__libc_start_main@GLIBC_2.2.5>
108e: f4 hlt
108f: 90 nop
0000000000001090 <deregister_tm_clones>:
1090: 48 8d 3d 79 2f 00 00 lea 0x2f79(%rip),%rdi # 4010 <__TMC_END__>
1097: 48 8d 05 72 2f 00 00 lea 0x2f72(%rip),%rax # 4010 <__TMC_END__>
109e: 48 39 f8 cmp %rdi,%rax
10a1: 74 15 je 10b8 <deregister_tm_clones+0x28>
10a3: 48 8b 05 2e 2f 00 00 mov 0x2f2e(%rip),%rax # 3fd8 <_ITM_deregisterTMCloneTable>
10aa: 48 85 c0 test %rax,%rax
10ad: 74 09 je 10b8 <deregister_tm_clones+0x28>
10af: ff e0 jmpq *%rax
10b1: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
10b8: c3 retq
10b9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
00000000000010c0 <register_tm_clones>:
10c0: 48 8d 3d 49 2f 00 00 lea 0x2f49(%rip),%rdi # 4010 <__TMC_END__>
10c7: 48 8d 35 42 2f 00 00 lea 0x2f42(%rip),%rsi # 4010 <__TMC_END__>
10ce: 48 29 fe sub %rdi,%rsi
10d1: 48 89 f0 mov %rsi,%rax
10d4: 48 c1 ee 3f shr $0x3f,%rsi
10d8: 48 c1 f8 03 sar $0x3,%rax
10dc: 48 01 c6 add %rax,%rsi
10df: 48 d1 fe sar %rsi
10e2: 74 14 je 10f8 <register_tm_clones+0x38>
10e4: 48 8b 05 05 2f 00 00 mov 0x2f05(%rip),%rax # 3ff0 <_ITM_registerTMCloneTable>
10eb: 48 85 c0 test %rax,%rax
10ee: 74 08 je 10f8 <register_tm_clones+0x38>
10f0: ff e0 jmpq *%rax
10f2: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
10f8: c3 retq
10f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001100 <__do_global_dtors_aux>:
1100: f3 0f 1e fa endbr64
1104: 80 3d 05 2f 00 00 00 cmpb $0x0,0x2f05(%rip) # 4010 <__TMC_END__>
110b: 75 2b jne 1138 <__do_global_dtors_aux+0x38>
110d: 55 push %rbp
110e: 48 83 3d e2 2e 00 00 cmpq $0x0,0x2ee2(%rip) # 3ff8 <__cxa_finalize@GLIBC_2.2.5>
1115: 00
1116: 48 89 e5 mov %rsp,%rbp
1119: 74 0c je 1127 <__do_global_dtors_aux+0x27>
111b: 48 8b 3d e6 2e 00 00 mov 0x2ee6(%rip),%rdi # 4008 <__dso_handle>
1122: e8 19 ff ff ff callq 1040 <__cxa_finalize@plt>
1127: e8 64 ff ff ff callq 1090 <deregister_tm_clones>
112c: c6 05 dd 2e 00 00 01 movb $0x1,0x2edd(%rip) # 4010 <__TMC_END__>
1133: 5d pop %rbp
1134: c3 retq
1135: 0f 1f 00 nopl (%rax)
1138: c3 retq
1139: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
0000000000001140 <frame_dummy>:
1140: f3 0f 1e fa endbr64
1144: e9 77 ff ff ff jmpq 10c0 <register_tm_clones>
0000000000001149 <main>:
1149: f3 0f 1e fa endbr64
114d: 55 push %rbp
114e: 48 89 e5 mov %rsp,%rbp
1151: 48 8d 3d ac 0e 00 00 lea 0xeac(%rip),%rdi # 2004 <_IO_stdin_used+0x4>
1158: e8 f3 fe ff ff callq 1050 <puts@plt>
115d: 90 nop
115e: 5d pop %rbp
115f: c3 retq
0000000000001160 <__libc_csu_init>:
1160: f3 0f 1e fa endbr64
1164: 41 57 push %r15
1166: 4c 8d 3d 4b 2c 00 00 lea 0x2c4b(%rip),%r15 # 3db8 <__frame_dummy_init_array_entry>
116d: 41 56 push %r14
116f: 49 89 d6 mov %rdx,%r14
1172: 41 55 push %r13
1174: 49 89 f5 mov %rsi,%r13
1177: 41 54 push %r12
1179: 41 89 fc mov %edi,%r12d
117c: 55 push %rbp
117d: 48 8d 2d 3c 2c 00 00 lea 0x2c3c(%rip),%rbp # 3dc0 <__do_global_dtors_aux_fini_array_entry>
1184: 53 push %rbx
1185: 4c 29 fd sub %r15,%rbp
1188: 48 83 ec 08 sub $0x8,%rsp
118c: e8 6f fe ff ff callq 1000 <_init>
1191: 48 c1 fd 03 sar $0x3,%rbp
1195: 74 1f je 11b6 <__libc_csu_init+0x56>
1197: 31 db xor %ebx,%ebx
1199: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
11a0: 4c 89 f2 mov %r14,%rdx
11a3: 4c 89 ee mov %r13,%rsi
11a6: 44 89 e7 mov %r12d,%edi
11a9: 41 ff 14 df callq *(%r15,%rbx,8)
11ad: 48 83 c3 01 add $0x1,%rbx
11b1: 48 39 dd cmp %rbx,%rbp
11b4: 75 ea jne 11a0 <__libc_csu_init+0x40>
11b6: 48 83 c4 08 add $0x8,%rsp
11ba: 5b pop %rbx
11bb: 5d pop %rbp
11bc: 41 5c pop %r12
11be: 41 5d pop %r13
11c0: 41 5e pop %r14
11c2: 41 5f pop %r15
11c4: c3 retq
11c5: 66 66 2e 0f 1f 84 00 data16 nopw %cs:0x0(%rax,%rax,1)
11cc: 00 00 00 00
00000000000011d0 <__libc_csu_fini>:
11d0: f3 0f 1e fa endbr64
11d4: c3 retq
Disassembly of section .fini:
00000000000011d8 <_fini>:
11d8: f3 0f 1e fa endbr64
11dc: 48 83 ec 08 sub $0x8,%rsp
11e0: 48 83 c4 08 add $0x8,%rsp
11e4: c3 retq
嵌入式开发
嵌入式开发是一种比较综合性的技术,它不单指纯粹的软件开发技术,也不单是一种硬件配置技术;它是在特定的硬件环境下针对某款硬件进行开发,是一种系统级别的与硬件结合比较紧密的软件开发技术。程序并不是运行在本地,而是运行在特殊的硬件上。
参与编译和运行的机器根据其角色可以分成以下三类:
-build系统:生成编译器可执行程序的计算机。编译器在build系统上编译出来的。
-host系统:运行编译器可执行程序,编译链接应用程序的计算机系统。
-target系统:运行应用程序的计算机系统。
根据build/host/target的不同组合我们可以得到如下的编译方式分类:
-本地(native)编译:build==host==target
-交叉(cross)编译:build==host!=target
whereis gcc
ls -l /usr/bin/gcc
ls -l /usr/bin/gcc-9
QEMU
QEMU是一套由(Fabrice Bellard)编写的以GPL许可证分发源码的计算机系统模拟软件,在GNU/Linux平台上使用广泛。
QEMU,支持多种体系架构。譬如:IA-32(x86),AMD 64, MIPS 32/64,RISC-V 32/64等等。
QEMU有两种主要运作模式:
-user mode: 直接运行应用程序 (比如说hello.o运行直接输出“hello”)
-system mode:模拟整个计算机系统,包括中央处理器及其他周边设备。
MAKE
make是一种自动化工程管理工具。
makefile由一条或者多条规则组成。
每条规则由三要素构成:
-target:目标,可以是obj文件也可以是可歘看文件。
-prerequisites:生成target所需要的依赖。
-command:为了生成target需要执行的命令,可以有多条。
模板:
target...:prerequisites...
command...
...
例子:
hello: hello.c
gcc hello.c -o hello
练习题
用riscv编译器编译hello.c,查看头信息、section信息和进行反汇编并查看c程序源码和机器指令的对应关系
$ riscv64-unknown-elf-gcc -o hello hello.c
$ readelf -h hello
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: RISC-V
Version: 0x1
Entry point address: 0x10116
Start of program headers: 64 (bytes into file)
Start of section headers: 22472 (bytes into file)
Flags: 0x5, RVC, double-float ABI
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 3
Size of section headers: 64 (bytes)
Number of section headers: 15
Section header string table index: 14
$ readelf -S hello
Section Headers:
[Nr] Name Type Address Offset
Size EntSize Flags Link Info Align
[ 0] NULL 0000000000000000 00000000
0000000000000000 0000000000000000 0 0 0
[ 1] .text PROGBITS 00000000000100e8 000000e8
00000000000024ee 0000000000000000 AX 0 0 2
[ 2] .rodata PROGBITS 00000000000125d8 000025d8
0000000000000012 0000000000000000 A 0 0 8
[ 3] .eh_frame PROGBITS 0000000000013000 00003000
0000000000000004 0000000000000000 WA 0 0 8
[ 4] .init_array INIT_ARRAY 0000000000013008 00003008
0000000000000010 0000000000000008 WA 0 0 8
[ 5] .fini_array FINI_ARRAY 0000000000013018 00003018
0000000000000008 0000000000000008 WA 0 0 8
[ 6] .data PROGBITS 0000000000013020 00003020
00000000000009a0 0000000000000000 WA 0 0 8
[ 7] .sdata PROGBITS 00000000000139c0 000039c0
0000000000000020 0000000000000000 WA 0 0 8
[ 8] .sbss NOBITS 00000000000139e0 000039e0
0000000000000038 0000000000000000 WA 0 0 8
[ 9] .bss NOBITS 0000000000013a18 000039e0
0000000000000588 0000000000000000 WA 0 0 8
[10] .comment PROGBITS 0000000000000000 000039e0
0000000000000034 0000000000000001 MS 0 0 1
[11] .riscv.attributes RISCV_ATTRIBUTE 0000000000000000 00003a14
000000000000004b 0000000000000000 0 0 1
[12] .symtab SYMTAB 0000000000000000 00003a60
00000000000015d8 0000000000000018 13 150 8
[13] .strtab STRTAB 0000000000000000 00005038
000000000000070c 0000000000000000 0 0 1
[14] .shstrtab STRTAB 0000000000000000 00005744
000000000000007e 0000000000000000 0 0 1
$ objdump -d hello
hello: file format elf64-little
objdump: can't disassemble for architecture UNKNOWN!