注意:其中一部分英文注释是我的塑料英文,主要是为了和源码一起看起来更和谐一点,很容易懂
实验做完了,才发现实验后网页有老师给的参考答案,哈哈反正我也不看,得记录一下,不记录就亏了。一天多时间都花在汇编上了

0 先上节目效果

1 修改屏幕上的开机Logo,设计一个自己的提示信息

①修改Linux源码0.11中bootsect.s末尾的msg1标号处的信息
msg1:.byte 13,10.ascii "DongZhaoChengOS is loading..." .byte 13,10,13,10
②修改Linux源码0.11中bootsect.s98行附近的汇编代码
 mov cx,#35mov   bx,#0x0007      ; page 0, attribute 7 (normal)mov   bp,#msg1mov ax,#0x1301      ; write string, move cursorint  0x10
注意:

cx的值应等于msg1 的长度,如上的cx = 35

解析:

调用了BIOS int 0x10中断,功能号:0x13,该中断在功能号为0x13时的调用规则可参考连接

在本例中
0x10是BIOS 中断号
ax=0x1301 也即 ah=0x13 al=0x01
ah=0x13 表示显示字符串的功能,ah用于指定功能号
al=0x01 表示设定的显示模式
bx=0x0007 也即 bh=0x00 bl=0x07
bh=0x00 表示页号
bl=0x07 表示属性
根据源码的上下文,此时es=0x9000
bp=#msg1 表示msg1在段中的偏移地址 es:bp表示msg1的寻址地址
cx表示要显示的字符数量

2 从bootsect.s载入setup.s程序时,屏幕输出一行"Now we are in SETUP…"信息,表示进入了setup部分

①修改Linux源码0.11中setup.s末尾,仿照bootsect.s,添加一个msg1
; HIT's OS experment 1.2: To disp a sentence is 'Now we are in SETUP...'  coding by dzc
msg1:.byte 13,10                            ; 回车、换行的ascii字符值.ascii "Now we are in SETUP...".byte 13,10,13,10.ascii "Memory Size(Get by dzc): "
注意:

上边的第5行是我为了在第3个要求准备的,也可以不加

②在setup.s程序的开头调用BIOS int 0x10中断以输出我们的字符msg1
; HIT's OS experment 1.2: To disp a sentence is 'Now we are in SETUP...'  coding by dzc   mov ax,#SETUPSEGmov es,ax       ; set segment offset to SETUPSEGmov ah,#0x03    ; ah is used to assign INT 0x10's func code; so we set ah = 0x03 to get cursor posxor bh,bh       ; now bh is input para : page numberint 0x10        ; call INT 0x10mov  cx,#53      ; cx is characters' lengthmov  bx,#0x0007  ; page 0, attribute 7 (normal)mov   bp,#msg1    ; es:bp is characters' addr, here es=#SETUPSEG=0x9020  bp= msg1 is offsetmov    ax,#0x1301  ; ah = 13 al = 01, 13 means disp something,01 means one of disp mode.int  0x10        ; call INT 0x10
注意:

这里模仿了bootsect.s中输出字符(汇编都是好几年前学的了,临时拿出来的,haha)

解析:

先调用了BIOS int 0x10中断,功能号:0x03,用于获取屏幕中的光标位置,之后的代码和bootsect.s相似

3 获取一个基本的硬件参数—如扩展内存的大小,并将其输出在屏幕上

①调用BIOS int 0x15中断,功能号:0x88获取扩展内存大小
; HIT's OS experment 1.3: To disp the extend memory size ,coding by dzcmov ah,#0x88int 0x15     ; get extend mem size in ax
注意:

这里的int 0x15中断,功能号:0x88、会将扩展内存的大小存放在ax通用寄存器中,具体请点击INT 0x15中断获取扩展内存大小

②利用用堆栈将ax中的16位二进制转换成10进制的ASCII码输出
; HIT's OS experment 1.3: To disp the extend memory size ,coding by dzcpush di          ; 因为后续代码中要暂时使用di作为计数器,但为了不破坏di中的原始数据,所以先将di压入堆栈mov di,#0      ; 清零dimov bx,#10    ; bx作为除数 10 PUSHTOSTACK:mov dx,#0       ; 清零dxdiv bx        ; dx:ax(32bit被除数) ÷ bx(16位除数) = ax(ax中存商).....dx(dx中存余数) push dx         ; 将余数压入堆栈inc di           ; di记录压栈次数 di=di+1cmp ax,#0           jne PUSHTOSTACK ; 这两句比较ax(商)是否为0; 若ax不等于0,则循环,jump到PUSHTOSTACK; 若ax等于0,顺序向下执行; ax is zero,so we can go down code!!!
POPSTACK:mov ah,#0x03       xor bh,bhint    0x10        ; 获取光标位置,注意该中断会更新cx的值,这也是为什么没有使用cx作为计数器的原因pop dx          ; 从堆栈中依次弹出值add dl,#0x30 ; dl也即dx的底8位存放了二进制值,再加上30H,得到该值的ASCII码; 例如.1(d) = 0000 0001(b) = 0x01 其ASCII码等于0x31 = 0x01 + 0x30mov al,dl        mov ah,#0x0E    int 0x10        ; 调用INT 0x10中断,功能号0x0E将该字符显示在光标位置dec di          ; di = di - 1,需要弹出堆栈的次数减1cmp di,#0       jne POPSTACK      ; 判断di是否为0,若di不为0,jump到POPSTACK继续循环; 若di为0,顺序执行下面的代码; From here, start print msg2 'KB.'etcmov    ah,#0x03    xor bh,bh       int 0x10        ; 获得光标位置mov cx,#7       mov bx,#0x0007  mov bp,#msg2    mov ax,#0x1301  int 0x10        ; 打印msg2 'KB.'pop di          ; 弹出堆栈中di,恢复di的值
注意:

为什么用di作为计数器?

  • di是我随便选了一个通用寄存器,主要是因为cx在循环过程中会被刷新,本来我用的是cx,发现一直出错,最后找出原因是cx被刷新了;当然选其他的通用寄存器也问题不大。

  • BIOS int 0x10中断,功能号0x0E的用法

    功能:

    ​ 在屏幕上显示字符并且将光标向前移动

    参数:

    ​ AL 待显示字符、BL前景色

    因此,每次调用前要先将要显示的字符的ASCII码存到AL中

4 setup.s 不再向下执行,将上述的信息显示在屏幕上停下即可

这个是最简单的了,直接在上述代码之后整个死循环就行了

INF_LOOP:jmp INF_LOOP    ; infinite loop

5 修改完代码后,对Linux 0.11内核进行编译,然后在Boshs中运行该小系统,效果如下

6 最后附上 bootsect.s 和 setup.s的代码

bootsect.s如下

;
; SYS_SIZE is the number of clicks (16 bytes) to be loaded.
; 0x3000 is 0x30000 bytes = 196kB, more than enough for current
; versions of linux
;
SYSSIZE = 0x3000
;
;   bootsect.s      (C) 1991 Linus Torvalds
;
; bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves
; iself out of the way to address 0x90000, and jumps there.
;
; It then loads 'setup' directly after itself (0x90200), and the system
; at 0x10000, using BIOS interrupts.
;
; NOTE; currently system is at most 8*65536 bytes long. This should be no
; problem, even in the future. I want to keep it simple. This 512 kB
; kernel size should be enough, especially as this doesn't contain the
; buffer cache as in minix
;
; The loader has been made as simple as possible, and continuos
; read errors will result in a unbreakable loop. Reboot by hand. It
; loads pretty fast by getting whole sectors at a time whenever possible..globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.textSETUPLEN = 4              ; nr of setup-sectors
BOOTSEG  = 0x07c0          ; original address of boot-sector
INITSEG  = 0x9000          ; we move boot here - out of the way
SETUPSEG = 0x9020          ; setup starts here
SYSSEG   = 0x1000          ; system loaded at 0x10000 (65536).
ENDSEG   = SYSSEG + SYSSIZE       ; where to stop loading; ROOT_DEV:  0x000 - same type of floppy as boot.
;       0x301 - first partition on first drive etc
ROOT_DEV = 0x306entry start
start:mov   ax,#BOOTSEGmov  ds,axmov    ax,#INITSEGmov  es,axmov    cx,#256sub  si,sisub    di,direpmovwjmpi    go,INITSEG
go: mov ax,csmov    ds,axmov    es,ax
; put stack at 0x9ff00.mov  ss,axmov    sp,#0xFF00      ; arbitrary value >>512; load the setup-sectors directly after the bootblock.
; Note that 'es' is already set up.load_setup:mov dx,#0x0000      ; drive 0, head 0mov    cx,#0x0002      ; sector 2, track 0mov  bx,#0x0200      ; address = 512, in INITSEG mov    ax,#0x0200+SETUPLEN    ; service 2, nr of sectorsint   0x13            ; read itjnc    ok_load_setup       ; ok - continuemov  dx,#0x0000mov   ax,#0x0000      ; reset the disketteint 0x13j   load_setupok_load_setup:; Get disk drive parameters, specifically nr of sectors/trackmov    dl,#0x00mov ax,#0x0800      ; AH=8 is get drive parametersint  0x13mov ch,#0x00seg csmov   sectors,cxmov   ax,#INITSEGmov  es,ax; Print some inane messagemov  ah,#0x03        ; read cursor posxor    bh,bh           ; bh = 0(dzc)int   0x10
; HIT's OS experience 1.1: To disp my custom logo like 'LOS loading...'etc. by dzcmov    cx,#35mov   bx,#0x0007      ; page 0, attribute 7 (normal)mov   bp,#msg1mov ax,#0x1301      ; write string, move cursorint  0x10; ok, we've written the message, now
; we want to load the system (at 0x10000)mov    ax,#SYSSEGmov   es,ax       ; segment of 0x010000call   read_itcall kill_motor; After that we check which root-device to use. If the device is
; defined (!= 0), nothing is done and the given device is used.
; Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending
; on the number of sectors that the BIOS reports currently.seg csmov    ax,root_devcmp  ax,#0jne    root_definedseg csmov   bx,sectorsmov   ax,#0x0208      ; /dev/ps0 - 1.2Mbcmp   bx,#15je    root_definedmov ax,#0x021c      ; /dev/PS0 - 1.44Mbcmp  bx,#18je    root_defined
undef_root:jmp undef_root
root_defined:seg csmov  root_dev,ax; after that (everyting loaded), we jump to
; the setup-routine loaded directly after
; the bootblock:jmpi    0,SETUPSEG; This routine loads the system at address 0x10000, making sure
; no 64kB boundaries are crossed. We try to load it as fast as
; possible, loading whole tracks whenever we can.
;
; in:   es - starting address segment (normally 0x1000)
;
sread:  .word 1+SETUPLEN   ; sectors read of current track
head:   .word 0         ; current head
track:  .word 0         ; current trackread_it:mov ax,estest ax,#0x0fff
die:    jne die         ; es must be at 64kB boundaryxor bx,bx      ; bx is starting address within segment
rp_read:mov ax,escmp ax,#ENDSEG     ; have we loaded all yet?jb ok1_readret
ok1_read:seg csmov ax,sectorssub ax,sreadmov cx,axshl cx,#9add cx,bxjnc ok2_readje ok2_readxor ax,axsub ax,bxshr ax,#9
ok2_read:call read_trackmov cx,axadd ax,sreadseg cscmp ax,sectorsjne ok3_readmov ax,#1sub ax,headjne ok4_readinc track
ok4_read:mov head,axxor ax,ax
ok3_read:mov sread,axshl cx,#9add bx,cxjnc rp_readmov ax,esadd ax,#0x1000mov es,axxor bx,bxjmp rp_readread_track:push axpush bxpush cxpush dxmov dx,trackmov cx,sreadinc cxmov ch,dlmov dx,headmov dh,dlmov dl,#0and dx,#0x0100mov ah,#2int 0x13jc bad_rtpop dxpop cxpop bxpop axret
bad_rt: mov ax,#0mov dx,#0int 0x13pop dxpop cxpop bxpop axjmp read_track/** This procedure turns off the floppy drive motor, so* that we enter the kernel in a known state, and* don't have to worry about it later.*/
kill_motor:push dxmov dx,#0x3f2mov al,#0outbpop dxretsectors:.word 0msg1:.byte 13,10.ascii "DongZhaoChengOS is loading...".byte 13,10,13,10.org 508
root_dev:.word ROOT_DEV
boot_flag:.word 0xAA55.text
endtext:
.data
enddata:
.bss
endbss:

setup.s如下

;
;   setup.s     (C) 1991 Linus Torvalds
;
; setup.s is responsible for getting the system data from the BIOS,
; and putting them into the appropriate places in system memory.
; both setup.s and system has been loaded by the bootblock.
;
; This code asks the bios for memory/disk/other parameters, and
; puts them in a "safe" place: 0x90000-0x901FF, ie where the
; boot-block used to be. It is then up to the protected mode
; system to read them from there before the area is overwritten
; for buffer-blocks.
;; NOTE; These had better be the same as in bootsect.s;INITSEG  = 0x9000   ; we move boot here - out of the way
SYSSEG   = 0x1000  ; system loaded at 0x10000 (65536).
SETUPSEG = 0x9020  ; this is the current segment.globl begtext, begdata, begbss, endtext, enddata, endbss
.text
begtext:
.data
begdata:
.bss
begbss:
.textentry start
start:
;----------------------------------------------------------
; HIT's OS experment 1.2: To disp a sentence is 'Now we are in SETUP...'  coding by dzc  mov ax,#SETUPSEGmov es,ax       ; set segment offset to SETUPSEGmov ah,#0x03    ; ah is used to assign INT 0x10's func code; so we set ah = 0x03 to get cursor posxor bh,bh       ; now bh is input para : page numberint 0x10        ; call INT 0x10mov  cx,#53      ; cx is characters' lengthmov  bx,#0x0007  ; page 0, attribute 7 (normal)mov   bp,#msg1    ; es:bp is characters' addr, here es=#SETUPSEG=0x9020  bp= msg1 is offsetmov    ax,#0x1301  ; ah = 13 al = 01, 13 means disp something,01 means one of disp mode.int  0x10        ; call INT 0x10
;-----------------------------------------------------------;------------Put this code at top ,it is okey!--------------
; HIT's OS experment 1.3: To disp the extend memory size ,coding by dzcmov ah,#0x88int 0x15        ; get extend mem size in axpush dimov di,#0     ; di is used to count timesmov bx,#10   ; bl is divisor and 8 bitPUSHTOSTACK:mov dx,#0div bx        ; ax is quotient  dx is divisor push dx          inc dicmp ax,#0            jne PUSHTOSTACK; ax is zero,so we can go down code!!!
POPSTACK:mov ah,#0x03       xor bh,bh       ; Get curcor pos,Func code 0x03 will change cx; So I use di as counter instead of cxint 0x10pop dx              add dl,#0x30    ; result in dl that is ASCII code of nummov al,dlmov ah,#0x0E   ; disp a char to screenint 0x10     ; CALL INT 0x10dec di       ; di = di - 1cmp di,#0       jne POPSTACK  ; From here, start print msg2 'KB.'etcmov ah,#0x03    xor bh,bh       int 0x10        mov cx,#7       mov bx,#0x0007  mov bp,#msg2    mov ax,#0x1301  int 0x10 pop di
; HIT's OS experment 1.3: To disp the extend memory size ,coding by dzc
INF_LOOP:jmp INF_LOOP   ; infinite loop
; ---------------------------------------------------------------; ok, the read went well so we get current cursor position and save it for
; posterity.mov ax,#INITSEG ; this is done in bootsect already, but...mov   ds,ax       ; #INITSEG IS 0x9000mov ah,#0x03    ; read cursor pos int 0x10 功能号:读光标xor    bh,bhint    0x10        ; save it in known place, con_init fetchesmov   [0],dx      ; it from 0x90000.; Get memory size (extended mem, kB)mov   ah,#0x88int 0x15mov [2],ax      ; now ax stores the size of extend memory in HEX; Get video-card data:mov   ah,#0x0fint 0x10mov [4],bx      ; bh = display pagemov [6],ax      ; al = video mode, ah = window width; check for EGA/VGA and some config parametersmov ah,#0x12mov bl,#0x10int 0x10mov [8],axmov   [10],bxmov  [12],cx; Get hd0 datamov    ax,#0x0000mov   ds,axlds    si,[4*0x41]mov  ax,#INITSEGmov  es,axmov    di,#0x0080mov   cx,#0x10repmovsb; Get hd1 datamov   ax,#0x0000mov   ds,axlds    si,[4*0x46]mov  ax,#INITSEGmov  es,axmov    di,#0x0090mov   cx,#0x10repmovsb; Check that there IS a hd1 :-)mov  ax,#0x01500mov  dl,#0x81int 0x13jc  no_disk1cmp ah,#3je is_disk1
no_disk1:mov    ax,#INITSEGmov  es,axmov    di,#0x0090mov   cx,#0x10mov ax,#0x00repstosb
is_disk1:; now we want to move to protected mode ...cli         ; no interrupts allowed ;; first we move the system to it's rightful placemov  ax,#0x0000cld           ; 'direction'=0, movs moves forward
do_move:mov es,ax       ; destination segmentadd    ax,#0x1000cmp   ax,#0x9000jz    end_movemov ds,ax       ; source segmentsub di,disub    si,simov    cx,#0x8000repmovswjmp   do_move; then we load the segment descriptorsend_move:mov   ax,#SETUPSEG    ; right, forgot this at first. didn't work :-)mov  ds,axlidt   idt_48      ; load idt with 0,0lgdt gdt_48      ; load gdt with whatever appropriate; that was painless, now we enable A20call  empty_8042mov   al,#0xD1        ; command writeout  #0x64,alcall    empty_8042mov   al,#0xDF        ; A20 onout #0x60,alcall    empty_8042; well, that went ok, I hope. Now we have to reprogram the interrupts :-(
; we put them right after the intel-reserved hardware interrupts, at
; int 0x20-0x2F. There they won't mess up anything. Sadly IBM really
; messed this up with the original PC, and they haven't been able to
; rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f,
; which is used for the internal hardware interrupts as well. We just
; have to reprogram the 8259's, and it isn't fun.mov  al,#0x11        ; initialization sequenceout    #0x20,al        ; send it to 8259A-1.word   0x00eb,0x00eb       ; jmp $+2, jmp $+2out #0xA0,al        ; and to 8259A-2.word   0x00eb,0x00ebmov    al,#0x20        ; start of hardware int's (0x20)out    #0x21,al.word   0x00eb,0x00ebmov    al,#0x28        ; start of hardware int's 2 (0x28)out  #0xA1,al.word   0x00eb,0x00ebmov    al,#0x04        ; 8259-1 is masterout   #0x21,al.word   0x00eb,0x00ebmov    al,#0x02        ; 8259-2 is slaveout    #0xA1,al.word   0x00eb,0x00ebmov    al,#0x01        ; 8086 mode for bothout #0x21,al.word   0x00eb,0x00ebout    #0xA1,al.word   0x00eb,0x00ebmov    al,#0xFF        ; mask off all interrupts for nowout    #0x21,al.word   0x00eb,0x00ebout    #0xA1,al; well, that certainly wasn't fun :-(. Hopefully it works, and we don't
; need no steenking BIOS anyway (except for the initial loading :-).
; The BIOS-routine wants lots of unnecessary data, and it's less
; "interesting" anyway. This is how REAL programmers do it.
;
; Well, now's the time to actually move into protected mode. To make
; things as simple as possible, we do no register set-up or anything,
; we let the gnu-compiled 32-bit programs do that. We just jump to
; absolute address 0x00000, in 32-bit protected mode.mov    ax,#0x0001  ; protected mode (PE) bitlmsw   ax      ; This is it;jmpi   0,8     ; jmp offset 0 of segment 8 (cs); This routine checks that the keyboard command queue is empty
; No timeout is used - if this hangs there is something wrong with
; the machine, and we probably couldn't proceed anyway.
empty_8042:.word    0x00eb,0x00ebin al,#0x64    ; 8042 status porttest  al,#2       ; is input buffer full?jnz  empty_8042  ; yes - loopretgdt:.word    0,0,0,0     ; dummy.word    0x07FF      ; 8Mb - limit=2047 (2048*4096=8Mb).word   0x0000      ; base address=0.word  0x9A00      ; code read/exec.word   0x00C0      ; granularity=4096, 386.word   0x07FF      ; 8Mb - limit=2047 (2048*4096=8Mb).word   0x0000      ; base address=0.word  0x9200      ; data read/write.word  0x00C0      ; granularity=4096, 386idt_48:.word    0           ; idt limit=0.word 0,0         ; idt base=0Lgdt_48:.word  0x800       ; gdt limit=2048, 256 GDT entries.word 512+gdt,0x9    ; gdt base = 0X9xxxxmsg1:.byte 13,10.ascii "Now we are in SETUP...".byte 13,10,13,10.ascii "Memory Size(Get by dzc): "msg2:.ascii "KB.".byte 13,10,13,10.text
endtext:
.data
enddata:
.bss
endbss:

哈工大操作系统实验:动手修改操作系统内核,自定义开机界面相关推荐

  1. 哈工大操作系统实验——实现proc文件系统

    哈工大操作系统实验--实现proc文件系统 参考文章: 操作系统实验08-proc文件系统的实现 在 Linux 0.11 上实现 procfs(proc 文件系统)内的 psinfo 结点.当读取此 ...

  2. 哈工大操作系统实验一——操作系统的引导

    写在前面 哈尔滨工业大学李治军老师的<操作系统>课程实验,相关资源: 哈工大操作系统实验手册 实验资源与参考 不配环境懒人福利:实验楼 在线课程:操作系统,李治军,哈工大(网易云课堂) 参 ...

  3. 哈工大操作系统实验1-操作系统引导

    哈工大操作系统实验1-操作系统引导 实验内容: 1. 改写 bootsect.s 主要完成如下功能: bootsect.s 能在屏幕上打印一段提示信息"XXX is booting...&q ...

  4. linux系统编程界面实验报告,操作系统实验报告-Linux操作使用编程.doc

    操作系统实验报告-Linux操作使用编程 实 验 报 告( 2012/ 2013 学年 第二学期) 课程名称操 作 系 统A实验名称Linux操作.使用.编程实验时间2013年 5 月 6日指导单位计 ...

  5. 【转载】笔记:计算机_体系结构_操作系统_软件_操作系统内核_GNU_Linux_C_Python_Latex_Java_TCP/IP_MacOS_Windows这些词语的历史,关系

    一.计算机的发明 世上本无路,走的人多了,就有了路.世上本无计算机,琢磨的人多了--没有计算机,一切无从谈起. 三个人对计算机的发明功不可没,居功至伟.阿兰·图灵(Alan Mathison Turi ...

  6. linux操作系统 抢占式,Linux操作系统内核抢占补丁的基本原理(2)

    Linux操作系统内核抢占补丁的基本原理(2) 2008-02-23 07:26:45来源:互联网 阅读 () int this_cpu, c; #ifdef CONFIG_PREEMPT ctx_s ...

  7. linux实验报告哈工大,哈工大操作系统实验---lab8:proc文件的实现

    文章目录 实验目的 掌握虚拟文件系统的实现原理 实践文件.目录.文件系统等概念 实验内容 在Linux0.11上实现procfs(proc文件系统)内的psinfo节点,当读取此节点的内容的时候,可得 ...

  8. 哈工大操作系统实验总结

    实验地址, https://www.lanqiao.cn/courses/115/learning/?id=374, 在现做实验, 好处是环境提前都配好了, 不足之处是敲代码有网络延迟, 环境无法保存 ...

  9. 哈工大操作系统实验4---基于内核栈切换的进程切换

    前置知识 关于栈桢 关于栈栈帧详解https://blog.csdn.net/ylyuanlu/article/details/18947951 进程切换流程 首先先了解一下进程切换的流程.开始的时候 ...

最新文章

  1. C#调用TSC条码打印机打印二维码(转)
  2. mysql-connector-net-6.7.4.msi,在ActiveReports中使用MySQL数据库
  3. 7 兼容 因特尔十代_年终抄底十代酷睿 请务必看看它……- ——快科技(驱动之家旗下媒体)-...
  4. 博弈论的局限性(博弈论的诡计)
  5. CNN中各类卷积总结:残差、shuffle、空洞卷积、变形卷积核、可分离卷积等
  6. rocketmq整合mysql事务_分布式事务(4)---RocketMQ实现分布式事务项目
  7. 代理服务器基本知识普及代理IP使用方法!
  8. 腾讯QQ表情生意经:建开放平台 与原创者最高六四分成
  9. Dual display on msm8937
  10. 用Python模拟高尔顿钉板实验
  11. 使用Google搜索引擎的10个搜索技巧
  12. K线形态分析交易系统
  13. 计算机双硬盘安装需要跳线吗,双硬盘安装的操作流程【详细步骤】
  14. 计算机无法关闭密码保护,win7的密码保护共享关闭不了怎么办_解决win7的密码保护共享关闭不了的方法...
  15. 最新Handsome主题V6.0免授权版+Typecho内核
  16. Linux 命令--SS
  17. 美通企业日报 | 陶氏杜邦完成对新陶氏的分拆;英特尔1.17亿美元投资14家创新公司...
  18. 【线性代数 宋浩】P3行列式的性质
  19. Springboot日志级别
  20. 吐槽Win7 x64资源管理器

热门文章

  1. 《杜拉拉升职记》之经典语录
  2. 微信公众号文章错别字修改上限调整了?
  3. 建筑的永恒之道----道
  4. 人月神话之七 未雨绸缪
  5. css outline是什么意思,用法
  6. 从零开始使用开源文档/Wiki软件 Outline(一)
  7. 用户名和计算机名命名规范
  8. linux里实现sl跑火车
  9. java8中mock静态方法,使用Mockk模拟静态Java方法
  10. JS_Detail和Discipline