Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

大佬,关于内核我有些问题 #17

Open
wjk13720041 opened this issue Sep 26, 2018 · 56 comments
Open

大佬,关于内核我有些问题 #17

wjk13720041 opened this issue Sep 26, 2018 · 56 comments
Labels

Comments

@wjk13720041
Copy link
Contributor

wjk13720041 commented Sep 26, 2018

1.我现在理解的内核加载是:bootloader把软盘里的内容加载到内存,然后跳转到ELF文件找到入口执行内核程序,但是不太清楚这里elf是自行进入脚本ld文件设置的入口还是需要我们给定入口位置

2.我现在是把bootloader分为boot和loader来写,boot主要把程序加载到内存,loader主要改显示模式,加载GDT表,开A20和切换保护模式等,我现在内存中的结构大概如此:
;0x7c00 boot
;0x7e00 loader
;0x8200 bios信息
;0x10000 内核

而GDT表现在是这样:
;gdt表
gdt: ;基地址 大小限制 这段的属性
gdt_null: Descriptor 0, 0, 0 ;空记录(基)
gdt_code: Descriptor 0, 0xfffff-1, DA_C+DA_32+DA_LIMIT_4K ;代码段
gdt_data: Descriptor 0, 0xfffff-1, DA_DRW+DA_32+DA_LIMIT_4K ;数据段

gdtLenght equ $-gdt
gdtLimit dw gdtLenght-1
gdtAddress dd gdt

;gdt选择子
selgdt_code equ gdt_code-gdt_null
selgdt_data equ gdt_data-gdt_null

然后我现在lgdt [gdtLimit] 后打算跳到内核执行
jmp dword selgdt_code:0x10000

但是貌似bochs又跳回了boot未启动的部分,也就是说重新加载了一遍程序,我想问一下大佬这里跳转部分我应该怎么做。bochs的GDT表好像和设置的不太一样,我现在总结出可能出现的问题:

1.我GDT设置有问题,基地址跳错位置了
2.我GDT表没设置上去
3.我跳转有问题
4.我从软盘加载到内存时候有问题

而其中内核加载到的内存地址我是boot中通过先将loader加载到0x7e00后将剩余部分全部加载到0x1000:0开始的位置

我下面会把boot和loader放上来,希望大佬给指点指点

@wjk13720041
Copy link
Contributor Author

wjk13720041 commented Sep 26, 2018

;boot.asm

;本文件主要是将主引导和内核读取到内存中

[BITS 16]

org 0x7c00

jmp startDash
nop

;FAT12信息
db "lovelive" ;生产厂商名
dw 512 ;每扇区字节数
db 1 ;每簇扇区数
dw 1 ;保留扇区数
db 2 ;FAT表份数
dw 224 ;根目录可容纳目录项数
dw 2880 ;总扇区数(16位)
db 0xf0 ;介质描述符
dw 9 ;每FAT使用的扇区数大小
dw 18 ;每个磁道的扇区数
dw 2 ;磁头数
dd 0 ;隐藏扇区数
dd 0 ;总扇区数(32位)
db 0 ;13号中断的驱动器号
db 0 ;保留
db 0x29 ;扩展引导标记
dd 0 ;卷序列号
db "boot ";卷标
db "FAT12 " ;文件系统类型

echo16: ;输出字符串
push ax
push bx
echoChar:
lodsb ;输入字符给al
or al,al ;自己或自己,不改变al值但是清理了符号位
jz bre ;到0了结束
mov ah,0x0e
mov bx,0x0f
int 0x10
jmp echoChar
bre:
pop bx
pop ax
ret

startDash:

mov ax,0
mov ss,ax
mov sp,0x7c00
mov ds,ax
mov es,ax


;mov al,0x03
;int 0x10

firstRead:
mov ax,0x07e0 ;7C00后面的位置,没占用
mov es,ax ;缓冲器基地址

mov ch,0       ;CH柱面
mov cl,2       ;CL扇区,现在这些代码位置在第一扇区,512B,load应该从第二扇区开始读取
mov dh,0       ;DH磁头号

Read:
mov si,0 ;用来记录读取出错的次数,每次成功读取一个簇会重置

ReadMain:
mov ah,0x02 ;int13的02号中断 读盘
mov al,1 ;一次读的扇区数
mov bx,0 ;缓冲区偏移量
mov dl,0 ;DL驱动号
int 0x13
jnc next ;没有出错就跳
add si,1 ;出错记录
cmp si,5 ;错误超过五次
jae fail ;结束程序运行顺便报错
mov ah,0x00 ;否则调int13的00号中断 复位
mov dl,0x00 ;复位内存地址
int 0x13
jmp ReadMain

next:
push si
mov si,msg_reading
call echo16
pop si

mov ax,es
cmp ax,0x07e0
je readCore
add ax,0x20 
jmp readNext

readCore:
mov ax,0x1000

readNext:
mov es,ax
add cl,1 ;开始搬运下一个扇区
cmp cl,18
jbe Read ;成功读完一个扇区,重置错误数并开始读取下一个扇区

mov cl,1    ;如果超过18个扇区,重置扇区号
add dh,1    ;然后开始读下一个面(也就是磁头号++)
cmp dh,1
jbe Read    ;如果磁头号在1以内(0,1两个磁头)就跳回和刚才一样读取这一面的内容

mov dh,0    ;成功读取一面后重置磁头号
add ch,1    ;开始换柱面读
cmp ch,10   ;读10个柱
jbe Read
jmp success

success: ;突然想加function(e){console.log(e)}
mov si,msg_readE
call echo16

jmp 0x7e00

fail:
mov si,msg_err
call echo16
jmp $

msg_reading:
db 46,0
msg_readE:
db 13,10,"read end!",13,10,0
msg_err:
db "error!",13,10,0

times 510-($-$$) db 0
db 0x55,0xaa

@wjk13720041
Copy link
Contributor Author

;loader.asm

;本文件主要加载GDT表IDT表,保存bios的信息,移动内核,切换保护模式和跳转到内核

;0x7c00 boot
;0x7e00 loader
;0x8200 bios信息
;0x10000 内核

%include "/home/lovelive/desktop/os/os/boot/pm.asm" ;引入oranges的常量表
[BITS 16]
LEDS equ 0x8200
VMODE equ 0x8202
SCRNX equ 0x8204
SCRNY equ 0x8206
VRAM equ 0x8208

jmp start

;gdt表
gdt: ;基地址 大小限制 这段的属性
gdt_null: Descriptor 0, 0, 0 ;空记录(基)
gdt_code: Descriptor 0, 0xfffff-1, DA_C+DA_32+DA_LIMIT_4K ;代码段
gdt_data: Descriptor 0, 0xfffff-1, DA_DRW+DA_32+DA_LIMIT_4K ;数据段

gdtLenght equ $-gdt
gdtLimit dw gdtLenght-1
gdtAddress dd gdt

;gdt选择子
selgdt_code equ gdt_code-gdt_null
selgdt_data equ gdt_data-gdt_null

start:
;切显示模式
;支持VBE -> VBS是2.0以上 -> 支持指定的显示模式 -> 用1024x768 8bit模式显示
;不支持就滚回320x200
;先做个判断,判断支持不支持vbe https://blog.csdn.net/happinux/article/details/5815914
mov ax,0x9000
mov es,ax
mov di,0
mov ax,0x4f00
int 0x10
cmp ax,0x004f
jne scr320x200 ;不支持,用320x200显示

mov ax,[es:di+4]
cmp ax,0x0200  ;判断vbe是不是2.0以上
jb scr320x200

mov cx,0x105   ;显示模式,1024x768 的 8bit模式(这里做判断,下面才是显示)
mov ax,0x4f01
int 0x10
cmp ax,0x004f  ;判断支持不支持
jne scr320x200

cmp byte [es:di+0x19],8 ;支持不支持8bit的颜色数
jne scr320x200
cmp byte [es:di+0x1b],4 ;调色板方法能不能用
jne scr320x200
mov ax,[es:di]          ;模式属性
and ax,0x0080           ;判断第7位是不是1
jz scr320x200

scr1024x768:
mov bx,0x4105
mov ax,0x4f02
int 0x10
mov byte [VMODE],8
mov ax,[es:di+0x12]
mov [SCRNX],ax
mov ax,[es:di+0x14]
mov [SCRNY],ax
mov eax,[es:di+0x28]
mov [VRAM],eax

jmp getKey

scr320x200:
mov al,0x13
mov ah,0x00
int 0x10
mov byte [VMODE],8
mov word [SCRNX],320
mov word [SCRNY],200
mov dword [VRAM],0x000a0000

getKey:
mov ah,0x02
int 0x16
mov [LEDS],al ;把键盘led信息写入内存

writeGDT: ;写gdt表

lgdt [gdtLimit]	
	
;开A20地址线
cli
in al,0x92  
or al,0x02
out 0x92,al 

;切保护模式
mov eax,cr0
or eax,1       ;控制寄存器0的最后一位是0则是实模式,1则是保护模式
mov cr0,eax

;jmp $

jmp dword selgdt_code:0x10000

times 512-($-$$) db 0

@wjk13720041
Copy link
Contributor Author

显示模式切换我是参考的《30天》,所以和大佬你现在的有些不同,大佬开始好像也是看的《30天》,然后loader我是对齐到了第二个扇区,这样我就直接把第二个扇区加到指定位置上,比较方便我操作

@wjk13720041
Copy link
Contributor Author

还有大佬,代码段中限长为0xfffff-1好像不够管理4G空间吧。。。

@wjk13720041
Copy link
Contributor Author

或者大佬,这么说吧。。。我之前在实模式下将内核加载到了0x10000开头的位置,我认为保护模式下GDT的起点是0x0000,那么我是不是将基指向gdt的data段然后跳转到0x10000就行,如果是那么ELF我需要如何执行?是直接将其装载到0X10000他就会被系统识别并通过找入口直接跳转到入口开始执行么?

@SilverRainZ
Copy link
Owner

Hello,我已经好几年没有继续研究 kernel 了,而且现在也没有从事相关的工作,
有些问题凭印象作答,难免有纰漏,太过细节的地方可能也无法深入研究,
因此这些回答仅供参考。

@wjk13720041
Copy link
Contributor Author

好的大佬

@SilverRainZ
Copy link
Owner

我现在理解的内核加载是:bootloader把软盘里的内容加载到内存,然后跳转到ELF文件找到入口执行内核程序,但是不太清楚这里elf是自行进入脚本ld文件设置的入口还是需要我们给定入口位置

你的理解大致没错,在 OS67 里,boot/bootsect.asm 会在实模式下把内核加载到 0x8000,开启保护模式并进入 32 位模式后之后跳转到 Selec_Code32_R0:0x8000 时,其控制流实际上是到了 kern/loader.asm 中,(loader.asm 会将内核整体从 0x8000 移到 0x100000,之所以这么做应该是由于 MBR 的历史原因)。

loader.asm 在这里是内核的一部分,和内核本体的 c 代码被编译成一个 binary,因此符号也是共享的,入口位置通过 [extern osmain] 伪指令即可获取。

@wjk13720041
Copy link
Contributor Author

大佬。。。[extern osmain] 不是引用一个外部定义了的函数么。。

@SilverRainZ
Copy link
Owner

Orz 好吧,看来我的理解有偏差,你要 ELF 入口点难道不是想找到内核代码开始的地方么?在没有 crt0 的情况下(其实我不知道有没有……),入口点不就是 main 函数么地址么?

对 OS67 来说并不存在什么 ELF 入口点,script/link.ld#L8 把内核的 .text 段安排在文件的最开始,生成一个 elf 格式的 kernel,然后 Makefile#L54 会把 elf 给 strip 成 binary,所以其实加载到内核的只是一个普通的 binary,它的 0x0 处就是 kernstart。

@SilverRainZ
Copy link
Owner

然后我现在lgdt [gdtLimit] 后打算跳到内核执行
jmp dword selgdt_code:0x10000
但是貌似bochs又跳回了boot未启动的部分,也就是说重新加载了一遍程序,我想问一下大佬这里跳转部分我应该怎么做。bochs的GDT表好像和设置的不太一样

你用 bochs 看过 GDT 表了么?建议用 bochsdbg 在 JMP 前加个 INT 3 断下来单步跟跟看。

😂 你贴的代码感觉我现在已经看不懂了,你列举的四个可能的问题,都可以通过 bochsdbg 来解决,当然由于 GDT 设置错误的问题可能调起来不是很直观。

@SilverRainZ
Copy link
Owner

SilverRainZ commented Sep 27, 2018

还有大佬,代码段中限长为0xfffff-1好像不够管理4G空间吧。。。

记得 DA_LIMIT_4K 也就是 Gr 位被置位的段的粒度是 4K 吧。

@SilverRainZ
Copy link
Owner

SilverRainZ commented Sep 27, 2018

我之前在实模式下将内核加载到了0x10000开头的位置,我认为保护模式下GDT的起点是0x0000,那么我是不是将基指向gdt的data段然后跳转到0x10000就行,如果是那么ELF我需要如何执行?是直接将其装载到0X10000他就会被系统识别并通过找入口直接跳转到入口开始执行么?

当然不「会被系统识别」,你就是系统,并没有一个第三者来帮你识别 elf 文件,除非你用更先进的 bootloader(比如基于 UEFI 的)。

如我刚才所说,OS67 的内核并不是一个 elf 文件,而是一个普通的 binary,因此与你现在的实现有出入,从汇编跳转到 C 代码这一段可能缺少参考价值。

对于 elf 来说,你直接跳转到 0x10000 也就是 elf 的 0x0 处当然是不行的,于渊的 Orange's 的做法是在汇编里解析 ELF 的 header,你可以参考看看,当年我看得很累于是采用了现在的做法……

@wjk13720041
Copy link
Contributor Author

那如果我采用打成一个elf或者其他文件然后加入镜像,并且不使用elf的格式,只相当于把内核打包成一个整体的文件,然后通过打包之后的地址进行访问不知道能不能成功,访问地址可以通过hexdump找到

@SilverRainZ
Copy link
Owner

应该可以,只要你保证总是能找到「入口点」,是什么格式都没所谓其实。

注意在跑 C 代码前先把其他的各种段基址设置好 kern/loader.asm#L21

@wjk13720041
Copy link
Contributor Author

我现在是学校有个编程活动,我想参加,之前抄了一遍30天的代码,但是那位大佬的编译器什么什么的全是他自带了。。。感觉抄一遍代码交了学到的东西不多,参加活动的诚意也不足,然后看了os67和neuos,都是类unix,没有图形化,然后我现在卡住了。。一个打包的问题,因为现在的格式是FAT12,需要按照文件系统格式保存,我现在是在centos下创建img然后挂载之后往里面存东西来打img的,然后现在又卡在了c编译成内核,我想的是c编译成bin然后c里面加个头来引用其他所有的内容

@wjk13720041
Copy link
Contributor Author

swcd5xr69oqjf3jbc2 2ij

@wjk13720041
Copy link
Contributor Author

谢谢大佬指点,我再去试试

@wjk13720041
Copy link
Contributor Author

我先试着保留boot.asm和loader.asm然后对齐两个文件到7c00和0x7e00然后将核心文件转成bin然后移动到0x10000处然后通过loader跳转到10000处试试

@SilverRainZ
Copy link
Owner

之前抄了一遍30天的代码,但是那位大佬的编译器什么什么的全是他自带了。。。感觉抄一遍代码交了学到的东西不多

看 30 天只能看到有趣的东西,重要的细节通通被作者藏起来了,这也是我放弃抄 SilverRainZ/OSASK 的原因。

我对这本书的看法:https://www.cnblogs.com/lastavengers/p/4115612.html

然后看了os67和neuos

neuos 是 @VOID001 那个么 😂 么?世界真小。

图形化

等你跨过保护模式和 C 语言的坎,开始做驱动,内存和进程部分的工作时,你会发现图形化实在算不得内核的一部分,尽管它也应该很有趣。

我现在是在centos下创建img然后挂载之后往里面存东西来打img的

这是科学的做法。

然后现在又卡在了c编译成内核,我想的是c编译成bin然后c里面加个头来引用其他所有的内容

可以参考下 loader.asm 是怎么做的,如果你不介意内核不是 elf 的话。

@wjk13720041
Copy link
Contributor Author

0.主要是第一次写,后面肯定会更加深入去了解
1.是那位大佬的。。。。b站貌似就那位大佬在写教程了。。。不过。。鸽了一年了。。如果大佬认识他麻烦帮忙催更。。
2.对的,不过现在主要是因为想做一个小型的,可以编辑简易文本的刷在U盘上面能直接跑起来带了一个简易文件系统的操作系统,所以就先把驱动和内核写一起了23333
3.但是貌似权限对他的影响特别大
4.好的大佬

@wjk13720041
Copy link
Contributor Author

wjk13720041 commented Sep 27, 2018

现在确实把指令加载到内存中了,我不再使用FAT12文件系统了

@wjk13720041
Copy link
Contributor Author

那应该就是GDT的问题,我现在加载到指定位置了但是没有跳转,我打算去掉保护模式进行一次实模式的跳转来验证正确性

@wjk13720041
Copy link
Contributor Author

image

@wjk13720041
Copy link
Contributor Author

成功

@VOID001
Copy link

VOID001 commented Sep 27, 2018

看到被 LA at 了,我就出来了 > <
@wjk13720041 除了自己写 bootloader 推荐另一个模式,使用 multiboot 标准构建你的镜像,这样你可以通过 grub 运行你的 os, 并且 grub 会帮你做很多初始化的事情
(其实我是想说之前一直工作+最近也很忙于是就咕咕咕neuos视频教程了,不过还是可以交流探讨的 :D)

@wjk13720041
Copy link
Contributor Author

看到被 LA at 了,我就出来了 > <
@wjk13720041 除了自己写 bootloader 推荐另一个模式,使用 multiboot 标准构建你的镜像,这样你可以通过 grub 运行你的 os, 并且 grub 会帮你做很多初始化的事情
(其实我是想说之前一直工作+最近也很忙于是就咕咕咕neuos视频教程了,不过还是可以交流探讨的 :D)

大师球

@wjk13720041
Copy link
Contributor Author

看到被 LA at 了,我就出来了 > <
@wjk13720041 除了自己写 bootloader 推荐另一个模式,使用 multiboot 标准构建你的镜像,这样你可以通过 grub 运行你的 os, 并且 grub 会帮你做很多初始化的事情
(其实我是想说之前一直工作+最近也很忙于是就咕咕咕neuos视频教程了,不过还是可以交流探讨的 :D)
这样其实也可以,但是我现在其实bootloader已经写好了,只是GDT加载部分有点问题,我直接用16进制写结果还是没办法跳过去,我现在如果可以跳到段的0x10000位置那么下面的我就有思路了,我可以达成二进制文件来运行,C的话我想如果引用把所有文件串联起来应该是可以的,就像os67这位大佬的软盘生成asm一样

@wjk13720041
Copy link
Contributor Author

还有大佬你们。。。貌似都不喜欢用QQ和微信。。。

@wjk13720041
Copy link
Contributor Author

大佬们。。睡了么。。没睡要不咱来讨论个问题? @SilverRainZ @VOID001
image
是这样,我不使用lgdt来设置gdtr就能正常加载GDT表。。。

@wjk13720041
Copy link
Contributor Author

我把代码整理一下贴在ubuntu pause吧,,,

@wjk13720041
Copy link
Contributor Author

这个是loader.asm
也就是主要切保护并跳到保护模式下的code段的代码
https://paste.ubuntu.com/p/pY9TSxW2fw/

@wjk13720041
Copy link
Contributor Author

其中我将lgdt注释掉了,现在这样的gdt最后加载了的话gdt表好像全是0

@wjk13720041
Copy link
Contributor Author

9 r3o vqs90 wgtb9 r_i
莫名其妙把几天的问题解决了

@VOID001
Copy link

VOID001 commented Sep 28, 2018

建议你用 Bochs 断点调试,看 gdtr 的地址是多少,并且用 bochs 打印出那个地址的 data 确认是否有误,GDT Table 和 GDT Descriptor 的 format 可以看 Intel 手册得知

@wjk13720041
Copy link
Contributor Author

建议你用 Bochs 断点调试,看 gdtr 的地址是多少,并且用 bochs 打印出那个地址的 data 确认是否有误,GDT Table 和 GDT Descriptor 的 format 可以看 Intel 手册得知

大佬,原因我查出来了,我看了一下gdtr的地址,是0x00a2,突然想到可能是因为加载到了内存的原因,因为他是在编译的时候确定的,所以我在开头加上了org 0x7e00这样他的地址就变成了0x7ea2,就可以正常读取到GDTR了

@wjk13720041
Copy link
Contributor Author

大佬,又遇到了新问题。。。
每次运行到下面这条指令--向0x000a0000写入的时候就会被重置(应该是被重置,跳到0xfffffff0,然后寄存器全清空)
qq 20180929121132
qq 20180929121257

@SilverRainZ
Copy link
Owner

感觉是数据段的属性没设置对,触发某硬件中断然后 reset 了?

@wjk13720041
Copy link
Contributor Author

感觉是数据段的属性没设置对,触发某硬件中断然后 reset 了?

大佬,这里的数据段是指elf数据段还是GDT表数据段呢。。

@wjk13720041
Copy link
Contributor Author

gdt
这个是gdt表部分

@wjk13720041
Copy link
Contributor Author

我试着向0x20000处写入但是还是reset了

@wjk13720041
Copy link
Contributor Author

gdt表也正常
gdt333333333

@SilverRainZ
Copy link
Owner

这里的数据段是指elf数据段还是GDT表数据段呢。。

GDT,你 ds 的值对得上么?

@VOID001
Copy link

VOID001 commented Sep 29, 2018

大佬,又遇到了新问题。。。
每次运行到下面这条指令--向0x000a0000写入的时候就会被重置(应该是被重置,跳到0xfffffff0,然后寄存器全清空)
qq 20180929121132
qq 20180929121257

看异常向量是多少,查手册看对应的错误是什么问题

@wjk13720041
Copy link
Contributor Author

这里的数据段是指elf数据段还是GDT表数据段呢。。

GDT,你 ds 的值对得上么?

ds是0x0000,能对上

@wjk13720041
Copy link
Contributor Author

大佬,又遇到了新问题。。。
每次运行到下面这条指令--向0x000a0000写入的时候就会被重置(应该是被重置,跳到0xfffffff0,然后寄存器全清空)
qq 20180929121132
qq 20180929121257

看异常向量是多少,查手册看对应的错误是什么问题

大佬劳烦问一下。。异常向量要怎么看。。。

@SilverRainZ
Copy link
Owner

ds是0x0000,能对上

0x0000 咋就对得上呢…… 保护模式下段寄存器不是段选择子的值么。

@wjk13720041
Copy link
Contributor Author

大佬我懂了,我ds应该设置gdt表中的段号,谢谢两位大佬的帮助 @SilverRainZ @VOID001

@wjk13720041
Copy link
Contributor Author

ds是0x0000,能对上

0x0000 咋就对得上呢…… 保护模式下段寄存器不是段选择子的值么。

我刚才发现了。。。。好丢脸啊、、、

@wjk13720041
Copy link
Contributor Author

wjk13720041 commented Sep 30, 2018

大佬们。。。我又带着问题来请教了。。。这次问题比较好玩。。。
首先。。先看下面的图,我现在在操作系统引入文字绘制部分,我检验过font和i的值都是正确的

xff2r 3lf7_9nw tb 4
xx7 _n8 cz ks cs kxb
我箭头指向的位置之前是ascii_font[font][i],作用是从ascii二进制字库取对应的二进制值,但是如果我font和i的位置只要有一个位置是填的变量名,就无法进行渲染

让我将两个空填了两个常数。。。奇迹发生了。。。。渲染正常了。。。??????

s3b4ogd8ranbbk5 ikh kwb
5026x g2 zzwa8gejja if1

然后我不信邪。。又把其中一个空填为变量。。。???又不能正常显示了。。

现在我觉得可能出现的情况都测试了,有几个猜想
1.是不是gcc有什么优化,讲一部分代码删去了
2.是不是链接的时候出了什么问题

想问一下大佬们发生过这种情况么

@wjk13720041
Copy link
Contributor Author

stsy_2m9 n 64xbj de sp8

汇编看着头都大了

https://paste.ubuntu.com/p/cx3ygNWQ34/

@wjk13720041
Copy link
Contributor Author

现在的情况就比如说,i是在0到15的范围变动的,5是包括在其中的,我把前面的font固定成图一的65,让i自行变动,如果成功那应该是至少有一行是有两个点的,但是。。完全没有。。。我是懵逼的。。代码没错但是结果就是出不来。。

@wjk13720041
Copy link
Contributor Author

箭头指向的上下都测试过了,都是正确的,就是指向的这行的两个空有问题。。。

@wjk13720041
Copy link
Contributor Author

测试的话无法输出数值,我是用二进制绘制变量自己的二进制码去读取变量数值的,看了是正确的

@wjk13720041
Copy link
Contributor Author

话说二维数组大小限制应该不会小到256*16吧。。我之前认为可能只加载10个柱面有数据没被加载进来,因为光ascii的点阵字库就12.0 KB,但是我加了读取的扇区,。。还是不行。。。

@wjk13720041
Copy link
Contributor Author

大佬。。过了。。我把字符数组的最后几排去掉就过了。。。?????一脸懵逼

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants