今天我想来点... Hello World!
又是快乐 Debug 的好日子呢!
昨天已经把程序跑起来了,
但又发现了很多奇怪的事情。
HEX Format 每个栏位到底代表什麽?
为什麽 Program Loader 跟 ELF 格式的开始位置对不起来?
真的要 * 16
吗?
今天就来尝试解开这些谜团吧!
可惜 HEX Format 的资料太零散,找到的原档连结也都失效,
只有第二手资讯真的不好整理,
找了很久 02
和 03
格式的用法还不够确定,
欢迎熟悉的朋友帮忙补充。
因为 Intel 官方和 Wikipedia 上面的运算都没写清楚,
我们参考 arm 的文件 HEX File Format,
很明显地跟程序写的一样,每一行都分成 00、02、03、04、05等 Type。
档案中包含了程序开始位置、资料位置以及内容等资讯。
HEX File 单行格式:
:llaaaatt[dd...]cc
:
每一行 HEX 格式的第一个字元固定都是这个ll
这一行的 [dd...] 有多少 byteaaaa
代表接下来的资料从哪个 address 开始tt
这一行後面的内容代表什麽[dd...]
这一行所带的资料cc
用来验证前面内容是否无误的 checksumHEX File 单行资料的意义是由 tt
栏位决定:
00
Data Record:10 0054 00 130101FD2326810213040103232EA4FC B2
10
代表有 16 byte 的资料0054
资料位置从 0x0054
开始00
这行的资料为 Data Record130101FD2326810213040103232EA4FC
16 byte 资料01
End-of-File (EOF) Record:00000001FF
02
Extended Segment Address Record:02 0000 02 1000 EC
02
代表有 2 byte 的资料0000
这边永远为 002
这行的资料为 Extended Segment Address1000
8086 segment 是 16-byte alignment03
Start Segment Address Record:04 0000 03 100000B8 31
04
代表有 4 byte 的资料0000
这边永远为 003
这行的资料为 Start Segment Address Record1000
8086 Code segment (CS)暂存器数值,是 16-byte alignment00B8
8086 Instruction pointer(IP) 暂存器数值04
Extended Address Record:02 0000 04 00FF FB
02
代表有 2 byte 的资料0000
这边永远为 002
这行的资料为 Extended Address Record00FF
代表最高的两个 byte offset,在这边是 0x00FF0000
05
Start Linear Address Record:04 0000 05 08000121 CD
04
代表有 4 byte 的资料0000
这边永远为 005
这行的资料为 Start Linear Address Record08000121
代表载入 8086 的 EIP 暂存器位置,也就是 32 bit Program Counter以下是这次的 hello.c 编译出来的 binary.hex
可以看到程序起始位置为 0x1000 * 16 + 0x00B8
= 0x1000B8
Extended Address 为 0x1000 * 16
= 0x100000
//binary.hex
type
||
:020000021000EC //extend segment address
:10005400130101FD2326810213040103232EA4FCB2 //data
:10006400232604FE6F0080028327C4FE0327C4FDF9 //data
:100074003307F700B7074000034707002380E70072 //data
:100084008327C4FE938717002326F4FE8327C4FE28 //data
:100094000327C4FDB307F70083C70700E39607FCF3 //data
:1000A40013000000138507000324C1021301010398 //data
:1000B40067800000130101FF23261100232481001F //data
:1000C40013040101B70701001385C70EEFF05FF8B1 //data
:1000D40093070000138507008320C10003248100D7 //data
:0800E400130101016780000017 //data
:0D00EC0068656C6C6F20776F726C6421008A //data
:04000003100000B831 //start segment address
:00000001FF //end of hex file
这下子终於看懂 /* ? */
是什麽意思了!
大概是因为原作者没用到所以不知道这行在干嘛XD
//RISC-V-TLM by mariusmm
uint32_t code_segment;
code_segment = stol(line.substr(9, 4), nullptr, 16) * 16; /* ? */
研究一下别人的 8086 assembly code 发现 Extended Segment Address 最终会放到 bp 内,
看起来是 Stack Frame 分隔的 Base Pointer,
有兴趣的人可以在该档案搜寻 "Intel-hex file" ,就可以看到了。
也就是说这两个分别是起始的 Program Counter 和 Stack Pointer 位置,
但这样一来,Program Memory Layout 又说不通了,
Stack Section 竟然是在比 Text Section 低的位置?
恩....看起来还要再花时间研究一下,
不过夜深了,猴子也累了,今天就先写到这里吧!
hello world 写起来很简单,
但是执行的时候却碰到问题:
没有看到预期的的字元被一个一个写进指定的 address。
第一个步骤就是把 hello.o 反组译之後一条一条指令核对!
Function Call 的 JAL
和 JALR
看起来没什麽问题,
就来看 printToTrace
的内容:
00010054 <printToTrace>:
printToTrace():
10054: fd010113 addi sp,sp,-48
10058: 02812623 sw s0,44(sp)
1005c: 03010413 addi s0,sp,48
10060: fca42e23 sw a0,-36(s0)
10064: fe042623 sw zero,-20(s0)
10068: 0280006f j 10090 <printToTrace+0x3c>
1006c: fec42783 lw a5,-20(s0)
10070: fdc42703 lw a4,-36(s0)
10074: 00f70733 add a4,a4,a5
10078: 004007b7 lui a5,0x400
1007c: 00074703 lbu a4,0(a4)
10080: 00e78023 sb a4,0(a5) # 400000 <__global_pointer$+0x3ee707>
10084: fec42783 lw a5,-20(s0)
10088: 00178793 addi a5,a5,1
1008c: fef42623 sw a5,-20(s0)
10090: fec42783 lw a5,-20(s0)
10094: fdc42703 lw a4,-36(s0)
10098: 00f707b3 add a5,a4,a5
1009c: 0007c783 lbu a5,0(a5)
100a0: fc0796e3 bnez a5,1006c <printToTrace+0x18>
100a4: 00000013 nop
100a8: 00078513 mv a0,a5
100ac: 02c12403 lw s0,44(sp)
100b0: 03010113 addi sp,sp,48
100b4: 00008067 ret
发现又是 branch 的时候出问题,
它竟然直接跳到下一行 0x10d4
结束 loop,
而不是跳到 0x1006c
执行 loop 内容!
rdValue: 0x3fff0 immValue: 0x30
current_pc: 0x10b4 target_pc: 0x10d4 JALR 1 0 0 rs1Value: 0x10d4 rs2Value: 0x0 r
但是东看西看,前天改 BNE
的没问题!
往回追一道指令,发现 LBU 拿到 0,
也就是说 "hello world!" 的位置从第一个 byte 就是 0,
那个 address... 是不是怪怪的啊!
0x100ec
看起来就跟 HEX File算出来的 main 起始位置 0x10b8
差很远,
肯定哪里怪怪的!
P.S.ADD
数值也怪怪的,不过是 Logger 的问题,先不理它!
current_pc: 0x1068 target_pc: 0x1090 JAL 0 8 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x28
current_pc: 0x1090 target_pc: 0x1094 LW 8 12 15 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x1094 target_pc: 0x1098 LW 8 28 14 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x100ec immValue: 0xffffffdc
current_pc: 0x1098 target_pc: 0x109c ADD 14 15 15 rs1Value: 0x100ec rs2Value: 0x100ec rdValue: 0x100ec immValue: 0x0
current_pc: 0x109c target_pc: 0x10a0 LBU 15 0 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x10a0 target_pc: 0x10a4 BNE 15 0 13 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xffffffcc
假设是 Data Section 拿错位置,
0x10b8
要对起来应该是 0x100b8
,
看起来是该改回 * 16
的时候了!
//memory.cpp
...
case 2: { //Extended segment address
extended_address = std::stoul(line.substr(9, 4), nullptr, 16) * 16;
}
break;
case 3: { //Start segment address
uint32_t code_segment = stoul(line.substr(9, 4), nullptr, 16) * 16;
...
Bingo!!!
果然是它!
前几天没有找到正确资料的报应立刻就来了。
之後好好地把 HEX Format Program Loader 修好吧!
github 页面 Tag: ITDay30
先在 Bus 里面加了一个简单的 console,
使用 Memory Mapped I/O 做法,
只要存取指定的 address space 就是存取指定的 I/O device。
本来打算另外写一篇完整一点的 External Device 章节,
但时间不太够,只能之後再补了。
//bus.cpp
...
switch (addr) {
case CONSOLE_BASE:
std::cout << "console: \'" << *reinterpret_cast<unsigned char*>(&data) << "\'" << std::endl;
break;
default:
memory_socket->b_transport(trans, delay);
break;
}
...
//bus.h
...
enum memoryMapp {
MEMORY_BASE = 0x000000,
CONSOLE_BASE = 0x400000,
};
...
程序非常简单,
就是把 "hello world!"
依序写入上面设定的 address。
//test.c
#define CONSOLE (*(unsigned char *)0x400000)
int printToTrace(char* input)
{
int i=0;
while(input[i] != '\0') {
CONSOLE = input[i];
i++;
}
}
int main()
{
printToTrace("hello world!");
return 0;
}
current_pc: 0x100b8 target_pc: 0x100bc ADDI 2 16 2 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x3fff0 immValue: 0xfffffff0
current_pc: 0x100bc target_pc: 0x100c0 SW 2 1 12 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xc
current_pc: 0x100c0 target_pc: 0x100c4 SW 2 8 8 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x8
current_pc: 0x100c4 target_pc: 0x100c8 ADDI 2 16 8 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x40000 immValue: 0x10
current_pc: 0x100c8 target_pc: 0x100cc LUI 2 0 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x10000 immValue: 0x10
current_pc: 0x100cc target_pc: 0x100d0 ADDI 15 12 10 rs1Value: 0x10000 rs2Value: 0x0 rdValue: 0x100ec immValue: 0xec
current_pc: 0x100d0 target_pc: 0x10054 JAL 31 5 1 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x100d4 immValue: 0xffffff84
current_pc: 0x10054 target_pc: 0x10058 ADDI 2 16 2 rs1Value: 0x3ffc0 rs2Value: 0x0 rdValue: 0x3ffc0 immValue: 0xffffffd0
current_pc: 0x10058 target_pc: 0x1005c SW 2 8 12 rs1Value: 0x3ffc0 rs2Value: 0x40000 rdValue: 0x0 immValue: 0x2c
current_pc: 0x1005c target_pc: 0x10060 ADDI 2 16 8 rs1Value: 0x3ffc0 rs2Value: 0x0 rdValue: 0x3fff0 immValue: 0x30
current_pc: 0x10060 target_pc: 0x10064 SW 8 10 28 rs1Value: 0x3fff0 rs2Value: 0x100ec rdValue: 0x0 immValue: 0xffffffdc
current_pc: 0x10064 target_pc: 0x10068 SW 8 0 12 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x10068 target_pc: 0x10090 JAL 0 8 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x28
current_pc: 0x10090 target_pc: 0x10094 LW 8 12 15 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x10094 target_pc: 0x10098 LW 8 28 14 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x100ec immValue: 0xffffffdc
current_pc: 0x10098 target_pc: 0x1009c ADD 14 15 15 rs1Value: 0x100ec rs2Value: 0x100ec rdValue: 0x100ec immValue: 0x0
current_pc: 0x1009c target_pc: 0x100a0 LBU 15 0 15 rs1Value: 0x68 rs2Value: 0x0 rdValue: 0x68 immValue: 0x0
current_pc: 0x100a0 target_pc: 0x1006c BNE 15 0 13 rs1Value: 0x68 rs2Value: 0x0 rdValue: 0x0 immValue: 0xffffffcc
current_pc: 0x1006c target_pc: 0x10070 LW 8 12 15 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x10070 target_pc: 0x10074 LW 8 28 14 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x100ec immValue: 0xffffffdc
current_pc: 0x10074 target_pc: 0x10078 ADD 14 15 14 rs1Value: 0x100ec rs2Value: 0x0 rdValue: 0x100ec immValue: 0x0
current_pc: 0x10078 target_pc: 0x1007c LUI 0 4 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x400000 immValue: 0x400
current_pc: 0x1007c target_pc: 0x10080 LBU 14 0 14 rs1Value: 0x68 rs2Value: 0x0 rdValue: 0x68 immValue: 0x0
console: h
...
console: e
...
console: l
...
console: l
...
console: o
...
console:
...
console: w
...
console: o
...
console: r
...
console: l
...
console: d
...
console: !
current_pc: 0x10080 target_pc: 0x10084 SB 15 14 0 rs1Value: 0x400000 rs2Value: 0x21 rdValue: 0x0 immValue: 0x0
current_pc: 0x10084 target_pc: 0x10088 LW 8 12 15 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0xb immValue: 0xffffffec
current_pc: 0x10088 target_pc: 0x1008c ADDI 15 1 15 rs1Value: 0xc rs2Value: 0x0 rdValue: 0xc immValue: 0x1
current_pc: 0x1008c target_pc: 0x10090 SW 8 15 12 rs1Value: 0x3fff0 rs2Value: 0xc rdValue: 0x0 immValue: 0xffffffec
current_pc: 0x10090 target_pc: 0x10094 LW 8 12 15 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0xc immValue: 0xffffffec
current_pc: 0x10094 target_pc: 0x10098 LW 8 28 14 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x100ec immValue: 0xffffffdc
current_pc: 0x10098 target_pc: 0x1009c ADD 14 15 15 rs1Value: 0x100ec rs2Value: 0x100f8 rdValue: 0x100f8 immValue: 0x0
current_pc: 0x1009c target_pc: 0x100a0 LBU 15 0 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x100a0 target_pc: 0x100a4 BNE 15 0 13 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xffffffcc
current_pc: 0x100a4 target_pc: 0x100a8 ADDI 0 0 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x100a8 target_pc: 0x100ac ADDI 15 0 10 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x100ac target_pc: 0x100b0 LW 2 12 8 rs1Value: 0x3ffc0 rs2Value: 0x0 rdValue: 0x40000 immValue: 0x2c
current_pc: 0x100b0 target_pc: 0x100b4 ADDI 2 16 2 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x3fff0 immValue: 0x30
current_pc: 0x100b4 target_pc: 0x100d4 JALR 1 0 0 rs1Value: 0x100d4 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x100d4 target_pc: 0x100d8 ADDI 0 0 15 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x100d8 target_pc: 0x100dc ADDI 15 0 10 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
current_pc: 0x100dc target_pc: 0x100e0 LW 2 12 1 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0xc
current_pc: 0x100e0 target_pc: 0x100e4 LW 2 8 8 rs1Value: 0x3fff0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x8
current_pc: 0x100e4 target_pc: 0x100e8 ADDI 2 16 2 rs1Value: 0x40000 rs2Value: 0x0 rdValue: 0x40000 immValue: 0x10
current_pc: 0x100e8 target_pc: 0x0 JALR 1 0 0 rs1Value: 0x0 rs2Value: 0x0 rdValue: 0x0 immValue: 0x0
INVALID: Opcode :0
Illegal Instruction, end simulation!
exception!
Info: /OSCI/SystemC: Simulation stopped by user.
花了 30 天,终於写出自己的 hello world 了。
最初的最初那篇,就是在哈罗。
只是踏着前人的足迹,用着前人留下的工具。
最後的最後这篇,还是在哈罗。
但这次不一样,
我们有了自己建立的工具,
还多了看着这篇文章的你我 :-D
>>: [Day29] 第二十九 - 补充技能交换前端以及与Express沟通api
Aloha~又是我少女人妻 Uerica!今天是教师节啊~大家小时候都会写感谢恩师的卡片吗?记得刚上...
前言 今天要来介绍一下 Python 中的各种变数型态,在程序中清楚了解自己要用的变数型态是非常重要...
前言 就小女子浅见,现在iOS开发有几个选项: React Native Flutter Swift...
终於~让我熬到最後一天了! 虽然订阅的人数最後还是屈指可数 但看着镜子中的自己体态变好,心情真的也跟...
後台 管理员能在後台页面查询用户购买纪录及明细 第一次进入此页面时无参数,在表单填入以下资讯後返回结...