系统环境:
OS:CentOS Stream release 9 (cmd: cat /etc/redhat-release)
Linux Kernel:Linux 5.14.0-142.el9.x86_64 (cmd: uname -a)

1. Bochs 虚拟机

Bochs 是一个开源的虚拟机软件,并且提供了利于系统开发的相关调试功能,如果你也是研究操作系统或对 Linux 内核感兴趣的读者,那么这款软件将会帮助你更好的调试和完善开发内容。
下载链接:
Bochs 官网:https://bochs.sourceforge.io/
Sourceforge下载:https://sourceforge.net/projects/bochs/files/bochs/
Github 下载:https://github.com/stlintel/Bochs

2. 编译并安装 Bochs

笔者选择在 sourceforge 上下载

2.2. 解压源码包

下载后需要解压源码包。

[imaginemiracle@imos-ws Downloads]$ tar -zxvf bochs-2.7.tar.gz

2.3. 安装依赖并配置 Bochs

安装相关依赖,否则配置或编译会出先缺少依赖的情况。

[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install gcc-c++
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install gtk2-devel
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install readline-devel
[imaginemiracle@imos-ws bochs-2.7]$ sudo yum install xorg-x11-server-Xdmx.x86_64

2.3.1. 使用 configure 配置生成 Makefile

进入解压后的源码目录,使用 configure 对源码进行配置,这里笔者使用 --prefix 将其安装目录配置为指定位置,不需要指定的读者可以不用加该参数。

[imaginemiracle@imos-ws bochs-2.7]$ ./configure --prefix=/pgm/bochs --with-x11 --with-wx --enable-debugger --enable-all-optimizations --enable-readline --enable-long-phy-address --enable-ltdl-install --enable-idle-hack --enable-a20-pin --enable-x86-64 --enable-smp --enable-cpu-level=6 --enable-large-ramfile --enable-repeat-speedups --enable-fast-function-calls  --enable-handlers-chaining  --enable-trace-linking --enable-configurable-msrs --enable-show-ips --enable-cpp --enable-debugger-gui --enable-iodebug --enable-logging --enable-assert-checks --enable-fpu --enable-vmx=2 --enable-svm --enable-3dnow --enable-alignment-check  --enable-monitor-mwait --enable-avx  --enable-evex --enable-x86-debugger --enable-pci --enable-usb --enable-voodoo

2.3.2. make 编译

配置没有报错后,便可以直接编译了。

[imaginemiracle@imos-ws bochs-2.7]$ make

2.3.3. 报错:No rule to make target ‘parser.cc’, needed by ‘parser.o’.

编译时可能会遇到这样或类似的错误:

make[1]: *** No rule to make target 'parser.cc', needed by 'parser.o'.  Stop.

2.3.4. 解决没有 parser.cc 问题

只需要将对应的 .cpp 文件拷贝为 .cc 文件即可:

[imaginemiracle@imos-ws bochs-2.7]$ cp bx_debug/parser.cpp bx_debug/parser.cc

[注]:不要疑问要怎么找到复制文件的目录所在。出错行紧后会提示从出错目录退出,这个目录便是缺少文件的目录,需要复制文件的目录也就在这里了。

2.3.5. 继续 make,继续报错:fatal error: config.h: No such file or directory

继续执行 make 命令,但是又会出现这样的错误:提示没有找到 config.h

cd bx_debug && \
make  libdebug.a
make[1]: Entering directory '/home/imaginemiracle/Downloads/bochs-2.7/bx_debug'
g++ -g -O2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES      -c -o parser.o parser.cc
In file included from parser.y:8:
debug.h:25:10: fatal error: config.h: No such file or directory25 | #include "config.h"|          ^~~~~~~~~~
compilation terminated.
make[1]: *** [<builtin>: parser.o] Error 1
make[1]: Leaving directory '/home/imaginemiracle/Downloads/bochs-2.7/bx_debug'
make: *** [Makefile:327: bx_debug/libdebug.a] Error 2

2.3.6. 解决没有找到 config.h 问题

关于这个头文件,我们在源码的主目录下可以看得到

[imaginemiracle@imos-ws bochs-2.7]$ ls
aclocal.m4      bxversion.rc     configure     gui           ltdl.c         osdep.cpp       README
bios            bxversion.rc.in  configure.in  host          ltdlconf.h     osdep.h         README-wxWidgets
bochs.h         CHANGES          COPYING       install-sh    ltdlconf.h.in  param_names.h   TESTFORM.txt
build           config.cpp       cpu           instrument    ltmain.sh      PARAM_TREE.txt  TODO
bx_debug        config.guess     cpudb.h       iodev         main.cpp       patches         win32_enh_dbg.rc
bxdisasm.cpp    config.h         crc.cpp       libtool       Makefile       pc_system.cpp   win32res.rc
bxthread.cpp    config.h.in      doc           LICENSE       Makefile.in    pc_system.h     wxbochs.rc
bxthread.h      config.log       docs-html     logio.cpp     memory         plugin.cpp
bxversion.h     config.status    extplugin.h   logio.h       misc           plugin.h
bxversion.h.in  config.sub       gdbstub.cpp   ltdl-bochs.h  msrs.def       qemu-queue.h

打开报错文件

[imaginemiracle@imos-ws bochs-2.7]$ vim bx_debug/debug.h

修改第 25 行的 #include "config.h"#include "../config.h" 即可。

2.3.7. 继续 make,继续报错:fatal error: osdep.h: No such file or directory 和 fatal error: cpu/decoder/decoder.h: No such file or directory

与上一个错误类似的还有两个,同样可以在主目录下找到 osdep.h,因此同样打开 bx_debug/debug.h#include “osdep.h” 修改为 #include "../osdep.h" ,第 36 行的 #include "cpu/decoder/decoder.h" 同样修改一下。

2.3.8. 继续 make,没错的话还会报错:No rule to make target ‘misc/bximage.cc’, needed by ‘misc/bximage.o’ 等一系列这样的问题

这类问题与第一个错误类似,在出错目录下也会有对应的 .cpp 文件,将其复制一份为 .cc 文件即可。

[imaginemiracle@imos-ws bochs-2.7]$ cp misc/bximage.cpp misc/bximage.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/hdimage.cpp iodev/hdimage/hdimage.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vmware3.cpp iodev/hdimage/vmware3.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vmware4.cpp iodev/hdimage/vmware4.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vpc.cpp iodev/hdimage/vpc.cc
[imaginemiracle@imos-ws bochs-2.7]$ cp iodev/hdimage/vbox.cpp iodev/hdimage/vbox.cc

2.3.9. 继续 make 没错后 make install 安装

这个时候执行 make 应该不会有错了,执行 make install 命令安装。

[imaginemiracle@imos-ws bochs-2.7]$ make install

查看一下安装目录,如果使用的是默认安装目录的话,则直接键入 boch 然后使用 tab 键可以补齐。

[imaginemiracle@imos-ws ~]$ ls /pgm/bochs/bin/
bochs  bximage

OK,如果看到有可执行文件生成到这里的话,那就说明 bochs 算是安装好了。

3. 制作软盘镜像文件

我们刚安装的 Bochs 配带了一个叫 bximage 的工具,这个工具变是用来创建虚拟机镜像的。

来看具体的使用方法:
(1) 直接执行 bximage(如果是像笔者一样安装到指定目录的话则首先需要将其添加进 在 ~/.bashrc 文件中,并更新环境变量 source ~/.bashrc,例:export PATH=$PATH:/pgm/bochs/bin

[imaginemiracle@imos-ws img]$ bximage
========================================================================bximageDisk Image Creation / Conversion / Resize and Commit Tool for Bochs$Id: bximage.cc 14091 2021-01-30 17:37:42Z sshwarts $
========================================================================1. Create new floppy or hard disk image
2. Convert hard disk image to other format (mode)
3. Resize hard disk image
4. Commit 'undoable' redolog to base image
5. Disk image info0. QuitPlease choose one [0] 1

(2) 这里输入 1,表示选择要创建一个软盘或者硬盘,按下回车则会出现如下内容;

Create imageDo you want to create a floppy disk image or a hard disk image?
Please type hd or fd. [hd] fd

(3) 这里让我们选择创建的类型是软盘 (fd) 还是硬盘 (hd),这里输入 fd 并回车;

Choose the size of floppy disk image to create.
Please type 160k, 180k, 320k, 360k, 720k, 1.2M, 1.44M, 1.68M, 1.72M, or 2.88M.[1.44M]

(4) 接下来会让选择创建的软盘大小,默认值是 1.44MB,这里直接回车使用默认值就好;

What should be the name of the image?
[a.img] imboot.imgCreating floppy image 'imboot.img' with 2880 sectorsThe following line should appear in your bochsrc:floppya: image="imboot.img", status=inserted

(5) 下一步会询问创建的软盘名字是什么,默认名为 a.img,这里笔者输入的名为 imboot.img,因为之后将会使用这个软盘作为一个 boot 程序用来启动操作系统使用。

ok,到这里软盘镜像文件创建完成。

4. Bochs 运行环境配置

Bochs 的安装目录下会提供一个供我们参考的一份配置文件 /pgm/bochs/share/doc/bochs/bochsrc-sample.txt,复制一份到本地来参考或者直接拷贝笔者的配置。

# Configuration file generated by Bochs
#=======================================================================
plugin_ctrl: unmapped=1, biosdev=1, speaker=1, extfpuirq=1, parallel=1, serial=1, iodebug=1config_interface: textconfig
#display_library: wx
display_library: xromimage: file=$BXSHARE/BIOS-bochs-latest, options=fastboot
romimage: file=/pgm/bochs/share/bochs/BIOS-bochs-latest
vgaromimage: file=/pgm/bochs/share/bochs/VGABIOS-lgpl-latest# choose the boot disk
boot: floppy
floppy_bootsig_check: disabled=0
floppya: type=1_44, 1_44=/home/imaginemiracle/Miracle/Projects/imOS/img/imboot.img, status=inserted, write_protected=0cpu: model=corei7_haswell_4770, count=1:1:1, ips=50000000, reset_on_triple_fault=1, ignore_bad_msrs=1, msrs="msrs.def"
cpu: cpuid_limit_winnt=0cpuid: x86_64=1, mmx=1, level=6, sep=1, simd=sse4_2, apic=xapic, aes=1, movbe=1, xsave=1, apic=x2apic, sha=1, adx=1, xsaveopt=1, avx_f16c=1, avx_fma=1, bmi=bmi2, 1g_pages=1, pcid=1, fsgsbase=1, smep=1, smap=1, mwait=1, vmx=1
cpuid: family=6, model=0x1a, stepping=5, vendor_string="GenuineIntel", brand_string="Intel(R) Core(TM) i7-4770 CPU (Haswell)"#memory: guest=512, host=256pci: enabled=1, chipset=i440fx
vga: extension=vbe, update_freq=5
#voodoo: enabled=1, model=voodoo1keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
mouse: enabled=0, type=ps2, toggle=ctrl+mbuttonclock: sync=none, time0=local, rtc_sync=0
#cmosimage: file=cmos.img, rtc_init=time0private_colormap: enabled=0ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=none
ata0-slave: type=none
ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=none
ata1-slave: type=none
ata2: enabled=0, ioaddr1=0x1e8, ioaddr2=0x3e0, irq=11
ata3: enabled=0, ioaddr1=0x168, ioaddr2=0x360, irq=9boot: floppy
#boot: disk
floppy_bootsig_check: disabled=0#log: /dev/null
log: bochsout.txt
logprefix: %t%e%dpanic: action=ask
error: action=report
info: action=report
debug: action=ignore, pci=report # report BX_DEBUG from module 'pci'debugger_log: -
#com1: enabled=1, mode=term, dev=/dev/ttyp9parport1: enabled=1, file="parport.out"#sound: driver=default, waveout=/dev/dsp. wavein=, midiout=
speaker: enabled=1, mode=system
parport1: enabled=1, file=none
parport2: enabled=0com1: enabled=1, mode=null
com2: enabled=0
com3: enabled=0
com4: enabled=0
#e1000: enabled=1, mac=52:54:00:12:34:56, ethmod=slirp, script=slirp.confmagic_break: enabled=0
#debug_symbols: file="kernel.sym"
print_timestamps: enabled=1
port_e9_hack: enabled=0
private_colormap: enabled=0megs: 2048

需要注意的是其中有一个 floppya 的配置,这里的镜像大小和文件路径是之前我们使用 bximage 工具创建出来的 imboot.img,这里的路径和大小一定要写正确,否则将无法启动。

floppya: type=1_44, 1_44=/home/imaginemiracle/Miracle/Project/imOS/img/imboot.img, status=inserted, write_protected=0

5. 写一个简单的 Boot 引导程序

新建并打开一个文件 imboot.S,编写基于 BIOSboot 代码:

org  0x7c00 ; BIOS 会加载引导程序到内存地址 0x7c00 处BaseOfStack  equ 0x7c00 ; 定义一个标识符 BaseOfStack,代表值 0x7c00Start:mov ax, cs  ; 将代码寄存器 cs 的段基地址设置到 ds、es、ss寄存器
mov ds, ax
mov es, ax
mov ss, ax
mov sp, BaseOfStack; 清屏mov ax, 0600h
mov bx, 0700h
mov cx, 0h
mov dx, 0184fh
int 10h; 设置光标位置mov ax, 0200h
mov bx, 0000h
mov dx, 0000h
int 10h; 在屏幕上打印字符串 "The imboot is working!"mov ax, 1301h
mov bx, 000fh
mov dx, 0000h
mov cx, 22
push ax
mov ax, ds
mov es, ax
pop ax
mov bp, IMBootMessage
int 10h; 软盘驱动器复位xor ah, ah
xor dl, dl
int 13hjmp $IMBootMessage:  dd  "The imboot is working!"; 填充 0 到结尾前 2 个字节times 510 - ($ - $$) db 0
dw 0xaa55   ; BIOS会检测软盘的第 0 磁头第 1 扇区最后两个字节是否为 0x55aa(代码中写成 0xaa55 是由于x86 使用小端存储),以确定这个扇区是否是引导扇区

这段汇编代码主要使用 BIOS 中断服务程序 int 10hint 13h 完成屏幕操作和驱动器复位的功能。

通过改变保存 int 10h 的主功能编号的 ah 寄存器使用不同功能,int 13h 也同样。

中断服务 主功能号 AH 功能描述 AL 功能 BH 功能 BL 功能 CH 功能 CL 功能 DH 功能 DL 功能 ES:BP

INT 10h
02h 设置光标位置 页码 - - - - 光标的列号 光标的行号 -
INT 10h 06h 按指定范围滚动窗口 滚动的列数;
0 表示清屏,此时其它属性无效
设置滚动后空出位置的属性
颜色属性:
* bit 0~2:字体颜色(0:黑1:蓝2:绿3:青4:红5:紫6:棕7:白)
* bit 3:字体亮度(0:默认1:高亮)
* bit 4~6:背景颜色(颜色的数值同上)
* bit 7:字体闪烁(0:关闭1:使能)
- 滚动范围的左上角坐标列号 滚动范围的左上角坐标行号 滚动范围右下角坐标列号 滚动范围右下角坐标行号 -
INT 10h 13h 显示一行字符串 写入模式:
00h: 字符串属性由 BL 控制,长度由 CX 控制(单位: Byte),不改变光标位置;
01h: 同上,但显示结束更新光标到字符串结尾处;
02h: 字符串由其最后的字节控制,CX 控制单位变为 Word,不改变光标位置;
03h: 同 02h,但更新光标位置到字符串结尾
页码 字符属性,同 06h 字符串长度 字符串长度 光标所在行号 光标所在列号 要显示字符串的内存地址
INT 13h 00h 重置磁盘驱动器 - - - - - - 00h: 第一个软盘驱动器( drive A: );
01h: 第二个软盘驱动器( drive B: );

7fh:第 128 个软盘驱动器;
80h: 第一个硬盘驱动器;

ffh:第128个硬盘驱动器
-

6. 在 Bochs 运行 Boot 程序

6.1. 下载安装 NASM 编译器

上面我们已经将代码写好了,但还未编译,编译会用到 NASM 编译器,先来安装它。
先安装其它依赖:如果是 Ubuntu 系统则可以直接使用 sudo apt-get install build-essential 即可

# Ubuntu 系统
imaginemiracle:~$ sudo apt-get install build-essential
imaginemiracle:~$ sudo apt-get install curl
# CentOS 系统
[imaginemiracle@imos-ws imboot]$ sudo yum install make automake gcc gcc-c++ kernel-devel
[imaginemiracle@imos-ws imboot]$ sudo yum install -y curl

下载并安装 nasm 编译器。

[imaginemiracle@imos-ws Downloads]$ curl -O -L https://www.nasm.us/pub/nasm/releasebuilds/2.15/nasm-2.15.tar.gz
[imaginemiracle@imos-ws Downloads]$ tar -zxvf nasm-2.15.tar.gz
[imaginemiracle@imos-ws Downloads]$ cd nasm-2.15/
[imaginemiracle@imos-ws nasm-2.15]$ ./autogen.sh
[imaginemiracle@imos-ws nasm-2.15]$ ./configure --prefix=/pgm/nasm
[imaginemiracle@imos-ws nasm-2.15]$ make install

添加 nasm 到环境变量中 vim ~/.bashrc,添加如下内容

export PATH=$PATH:/pgm/bochs/bin:/pgm/nasm/bin

更新环境变量

source ~/.bashrc

6.2. 编译程序并烧写进软盘

用刚刚安装好的 nasm 工具编译 boot 代码:

[imaginemiracle@imos-ws imboot]$ nasm imboot.S -o imboot.bin
[imaginemiracle@imos-ws imboot]$ ls
imboot.bin  imboot.S

编译将会生成一个二进制文件,将这个文件烧写进之前制作好的 imboot.img 软盘中:

[imaginemiracle@imos-ws img]$ dd if=../imboot/imboot.bin of=./imboot.img bs=512 count=1 conv=notrunc
1+0 records in
1+0 records out
512 bytes copied, 0.000104768 s, 4.9 MB/s

打开镜像文件 imboot.img 检验烧写或者代码编写是否正确。

[imaginemiracle@imos-ws img]$ vim imboot.img

因为文件是二进制文件,因此打开后会看到 “乱码” 的现象,没关系,使用 %!xxd 工具即可将其转换为 16 进制查看。

转换后,我们就可以看到如下内容。

我们需要检验的主要是该软盘的第一个扇区最后两个字节是否为 0x55aa,这是标识着是否作为引导扇区的结尾。一个扇区大小为 512 字节,这里的一行有 16 个字节,因此第 511512 字节应该会出现在第 32 行的末尾。(512 / 16 = 32

ok,看起来我们的代码和烧写是没有问题的,可以继续下一步了。

7. 用 Bochs 启动我们的 Boot 代码

使用 bochs 命令并指定配置文件为之前写好的配置文件。

[imaginemiracle@imos-ws bochs-run]$ bochs -f bochsrc

运行后将会有如下输出:

========================================================================Bochs x86 Emulator 2.7Built from SVN snapshot on August  1, 2021Timestamp: Sun Aug  1 10:07:00 CEST 2021
========================================================================
00000000000i[      ] BXSHARE not set. using compile time default '/pgm/bochs/share/bochs'
00000000000i[      ] reading configuration from bochsrc
00000000000i[      ] Ignoring magic break points
------------------------------
Bochs Configuration: Main Menu
------------------------------This is the Bochs Configuration Interface, where you can describe the
machine that you want to simulate.  Bochs has already searched for a
configuration file (typically called bochsrc.txt) and loaded it if it
could be found.  When you are satisfied with the configuration, go
ahead and start the simulation.You can also start bochs with the -q option to skip these menus.1. Restore factory default configuration
2. Read options from...
3. Edit options
4. Save options to...
5. Restore the Bochs state from...
6. Begin simulation
7. Quit nowPlease choose one: [6]

这里默认的选择是 6,正是开始运行我们给的镜像文件,因此这里直接输入回车即可。

这个时候应该会看到一个黑屏的界面,这个时候需要继续在命令行中输入 ccontinue 来告诉 bochs 运行 boot 程序。

这个时候可以看到代码中的字符串 The imboot is working! 已经被打印了出来,就说明 Boot 程序已经执行了。

#本文完

到此你已经掌握了 BIOSboot 程序的工作流程,以及在虚拟机上的实际模拟。

觉得这篇文章对你有帮助的话,就留下一个赞吧^v^*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/126260487

【实现操作系统 01】CentOS 9 安装配置 Bochs 2.7 虚拟机,及编写简单的 bootloader 并写入软盘启动相关推荐

  1. 在Linux下安装配置bochs,并成功跑一个简单的boot引导(超详细)

    环境:centos7(建议带桌面的版本)镜像网址 环境配置:gcc.gas.nasm.make 1.配置环境 yum -y install xxx(eg:gcc.等) 若出现yum源问题请观看 没有可 ...

  2. 虚拟化操作系统ESXi 6.7安装配置--vSphere

    虚拟化操作系统ESXi 6.7安装配置 vSphere是VNware公司在2001年基于云计算推出的一套企业级虚拟化解决方案.核心组件为ESXi.如今,经历了5个版本的改进,已经实现了虚拟化基础架构. ...

  3. Centos 6 安装 配置 oracle11g R2

    Centos 6 安装 配置 oracle11g R2 分享到:0 分类:                          Linux&CentosOracle 1.安装centos6.3_ ...

  4. CentOS 7 安装配置 NFS

    CentOS 7  安装配置 NFS 环境 nps 192.168.1.97 client 192.168.1.98 一.yum 安装 yum -y install nfs-utils rpcbind ...

  5. Linux 实操———CentOS 6 安装配置 Tomcat

    引言 Linux下安装Tomcat. 一.下载.传输与解压 同<Linux 实操---CentOS 6 安装配置 Oracle JDK 1.8>一样,前期都是先在远程机上下载压缩包,然后通 ...

  6. centos 7安装配置python3.7

    centos 7安装配置python3.7(亲测) 默认版本为python2.7 (1)下载python版本 wget https://www.python.org/ftp/python/3.7.3/ ...

  7. centos 一键安装配置nginx脚本

    centos 一键安装配置nginx脚本 installNginx.ssh 用vi或则vim编辑 installNginx.ssh #!/bin/bash # author:kwin # Email: ...

  8. CentOS 6 安装Hadoop 2.6 (四)运行简单例子

    CentOS 6 安装Hadoop 2.6 (一)准备工作 CentOS 6 安装Hadoop 2.6 (二)配置Hadoop CentOS 6 安装Hadoop 2.6 (三)问题收集 CentOS ...

  9. centos编译安装配置支持ssl加密的mysql replication

    参考文章:http://www.howtoforge.com/how-to-set-up-mysql-database-replication-with-ssl-encryption-on-cento ...

最新文章

  1. Scrapy入门(二)创建Scrapy项目
  2. SOA技术相关介绍(RPC, Web Service, REST,SOAP,JMI)
  3. 落实业务服务管理从基础设施管理做起
  4. NAT综合实验(华为)
  5. Linux命令学习系列-用户切换su,sudo
  6. raize控件的安装注意
  7. 净资产收益率ROE连续3年超过15%的股票排名
  8. DFI(Deep/DynamicFlow Inspection,深度/动态流检测)
  9. 计算机原理与智能-翻译
  10. 程序员的“荣”与“耻”之我见
  11. 你的名字烂大街了吗?数据揭开国人起名背后的秘密……
  12. 【百问网7天物联网智能家居】训练营学习笔记(七)
  13. 飞龙射击(Unity2D入门小游戏)
  14. 解决Unexpected end of JSON input while parsing near的报错问题
  15. web方向是.NET好还是java好_C#和.NET向JAVA好转吗?
  16. 从零开始搭建一个项目-前端框架(vue)
  17. 如何撰写商业计划书?
  18. 了解MySQL(超详细的MySQL工作原理 体系结构)
  19. 超级应用程序的图标设计系统
  20. echarts字体设置

热门文章

  1. 1.0 工厂模式-简单工厂
  2. 于丹教授360个让人流泪的句子
  3. 困惑我们人生的62个问题答案
  4. android Glide 4.0图片加载失败
  5. python自动回复qq消息_基于python使用qqbot接入qq做一个简单的文字消息自动回复
  6. InsecureDeserialization(不安全的反序列化)
  7. C++函数返回引用和值问题
  8. 想问【星图地球开发者平台】能按需自定义组合组件吗?
  9. 苹果隐私十年史:变与不变(1)突变与营销
  10. 厦门网中网软件有限公司