第十八课 特权级转移(上)

这一节我们来研究从核心代码特权级转移到应用代码特权级。

首先将boot.asm贴出来如下:

  1 org 0x7c00
  2
  3 jmp short start
  4 nop
  5
  6 define:
  7     BaseOfStack      equ 0x7c00
  8     BaseOfLoader     equ 0x9000
  9     RootEntryOffset  equ 19
 10     RootEntryLength  equ 14
 11     EntryItemLength  equ 32
 12     FatEntryOffset   equ 1
 13     FatEntryLength   equ 9
 14
 15 header:
 16     BS_OEMName     db "D.T.Soft"
 17     BPB_BytsPerSec dw 512
 18     BPB_SecPerClus db 1
 19     BPB_RsvdSecCnt dw 1
 20     BPB_NumFATs    db 2
 21     BPB_RootEntCnt dw 224
 22     BPB_TotSec16   dw 2880
 23     BPB_Media      db 0xF0
 24     BPB_FATSz16    dw 9
 25     BPB_SecPerTrk  dw 18
 26     BPB_NumHeads   dw 2
 27     BPB_HiddSec    dd 0
 28     BPB_TotSec32   dd 0
 29     BS_DrvNum      db 0
 30     BS_Reserved1   db 0
 31     BS_BootSig     db 0x29
 32     BS_VolID       dd 0
 33     BS_VolLab      db "D.T.OS-0.01"
 34     BS_FileSysType db "FAT12   "
 35
 36 start:
 37     mov ax, cs
 38     mov ss, ax
 39     mov ds, ax
 40     mov es, ax
 41     mov sp, BaseOfStack
 42
 43     mov ax, RootEntryOffset
 44     mov cx, RootEntryLength
 45     mov bx, Buf
 46
 47     call ReadSector
 48
 49     mov si, Target
 50     mov cx, TarLen
 51     mov dx, 0
 52
 53     call FindEntry
 54
 55     cmp dx, 0
 56     jz output
 57
 58     mov si, bx
 59     mov di, EntryItem
 60     mov cx, EntryItemLength
 61
 62     call MemCpy
 63
 64     mov ax, FatEntryLength
 65     mov cx, [BPB_BytsPerSec]
 66     mul cx
 67     mov bx, BaseOfLoader
 68     sub bx, ax
 69
 70     mov ax, FatEntryOffset
 71     mov cx, FatEntryLength
 72
 73     call ReadSector
 74
 75     mov dx, [EntryItem + 0x1A]
 76     mov si, BaseOfLoader
 77
 78 loading:
 79     mov ax, dx
 80     add ax, 31
 81     mov cx, 1
 82     push dx
 83     push bx
 84     mov bx, si
 85     call ReadSector
 86     pop bx
 87     pop cx
 88     call FatVec
 89     cmp dx, 0xFF7
 90     jnb BaseOfLoader
 91     add si, 512
 92     jmp loading
 93
 94 output:
 95     mov bp, MsgStr
 96     mov cx, MsgLen
 97     call Print
 98
 99 last:
100     hlt
101     jmp last
102
103
104 ; cx --> index
105 ; bx --> fat table address
106 ;
107 ; return:
108 ;     dx --> fat[index]
109 FatVec:
110     mov ax, cx
111     mov cl, 2
112     div cl
113
114     push ax
115
116     mov ah, 0
117     mov cx, 3
118     mul cx
119     mov cx, ax
120
121     pop ax
122
123     cmp ah, 0
124     jz even
125     jmp odd
126
127 even:    ; FatVec[j] = ( (Fat[i+1] & 0x0F) << 8 ) | Fat[i];
128     mov dx, cx
129     add dx, 1
130     add dx, bx
131     mov bp, dx
132     mov dl, byte [bp]
133     and dl, 0x0F
134     shl dx, 8
135     add cx, bx
136     mov bp, cx
137     or  dl, byte [bp]
138     jmp return
139
140 odd:     ; FatVec[j+1] = (Fat[i+2] << 4) | ( (Fat[i+1] >> 4) & 0x0F );
141     mov dx, cx
142     add dx, 2
143     add dx, bx
144     mov bp, dx
145     mov dl, byte [bp]
146     mov dh, 0
147     shl dx, 4
148     add cx, 1
149     add cx, bx
150     mov bp, cx
151     mov cl, byte [bp]
152     shr cl, 4
153     and cl, 0x0F
154     mov ch, 0
155     or  dx, cx
156
157 return:
158     ret
159
160 ; ds:si --> source
161 ; es:di --> destination
162 ; cx    --> length
163 MemCpy:
164
165     cmp si, di
166
167     ja btoe
168
169     add si, cx
170     add di, cx
171     dec si
172     dec di
173
174     jmp etob
175
176 btoe:
177     cmp cx, 0
178     jz done
179     mov al, [si]
180     mov byte [di], al
181     inc si
182     inc di
183     dec cx
184     jmp btoe
185
186 etob:
187     cmp cx, 0
188     jz done
189     mov al, [si]
190     mov byte [di], al
191     dec si
192     dec di
193     dec cx
194     jmp etob
195
196 done:
197     ret
198
199 ; es:bx --> root entry offset address
200 ; ds:si --> target string
201 ; cx    --> target length
202 ;
203 ; return:
204 ;     (dx !=0 ) ? exist : noexist
205 ;        exist --> bx is the target entry
206 FindEntry:
207     push cx
208
209     mov dx, [BPB_RootEntCnt]
210     mov bp, sp
211
212 find:
213     cmp dx, 0
214     jz noexist
215     mov di, bx
216     mov cx, [bp]
217     push si
218     call MemCmp
219     pop si
220     cmp cx, 0
221     jz exist
222     add bx, 32
223     dec dx
224     jmp find
225
226 exist:
227 noexist:
228     pop cx
229
230     ret
231
232 ; ds:si --> source
233 ; es:di --> destination
234 ; cx    --> length
235 ;
236 ; return:
237 ;        (cx == 0) ? equal : noequal
238 MemCmp:
239
240 compare:
241     cmp cx, 0
242     jz equal
243     mov al, [si]
244     cmp al, byte [di]
245     jz goon
246     jmp noequal
247 goon:
248     inc si
249     inc di
250     dec cx
251     jmp compare
252
253 equal:
254 noequal:
255
256     ret
257
258 ; es:bp --> string address
259 ; cx    --> string length
260 Print:
261     mov dx, 0
262     mov ax, 0x1301
263     mov bx, 0x0007
264     int 0x10
265     ret
266
267 ; no parameter
268 ResetFloppy:
269
270     mov ah, 0x00
271     mov dl, [BS_DrvNum]
272     int 0x13
273
274     ret
275
276 ; ax    --> logic sector number
277 ; cx    --> number of sector
278 ; es:bx --> target address
279 ReadSector:
280
281     call ResetFloppy
282
283     push bx
284     push cx
285
286     mov bl, [BPB_SecPerTrk]
287     div bl
288     mov cl, ah
289     add cl, 1
290     mov ch, al
291     shr ch, 1
292     mov dh, al
293     and dh, 1
294     mov dl, [BS_DrvNum]
295
296     pop ax
297     pop bx
298
299     mov ah, 0x02
300
301 read:
302     int 0x13
303     jc read
304
305     ret
306
307 MsgStr db  "No LOADER ..."
308 MsgLen equ ($-MsgStr)
309 Target db  "LOADER     "
310 TarLen equ ($-Target)
311 EntryItem times EntryItemLength db 0x00
312 Buf:
313     times 510-($-$$) db 0x00
314     db 0x55, 0xaa

inc.asm如下:

 1 ; Segment Attribute
 2 DA_32    equ    0x4000
 3 DA_DR    equ    0x90
 4 DA_DRW   equ    0x92
 5 DA_DRWA  equ    0x93
 6 DA_C     equ    0x98
 7 DA_CR    equ    0x9A
 8 DA_CCO   equ    0x9C
 9 DA_CCOR  equ    0x9E
10
11 ; Segment Privilege
12 DA_DPL0  equ   0x00        ; DPL = 0
13 DA_DPL1  equ   0x20        ; DPL = 1
14 DA_DPL2  equ   0x40        ; DPL = 2
15 DA_DPL3  equ   0x60        ; DPL = 3
16
17 ; Special Attribute
18 DA_LDT             equ        0x82
19 DA_TaskGate        equ        0x85    ;
20 DA_386TSS        equ        0x89    ;
21 DA_386CGate        equ        0x8C    ;
22 DA_386IGate        equ        0x8E    ;
23 DA_386tgATE        equ        0x8F    ;
24
25 ; Selector Attribute
26 SA_RPL0    equ    0
27 SA_RPL1    equ    1
28 SA_RPL2    equ    2
29 SA_RPL3    equ    3
30
31 SA_TIG    equ    0
32 SA_TIL    equ    4
33
34 ; 描述符
35 ; usage: Descriptor Base, Limit, Attr
36 ;        Base:  dd
37 ;        Limit: dd (low 20 bits available)
38 ;        Attr:  dw (lower 4 bits of higher byte are always 0)
39 %macro Descriptor 3                              ; 段基址, 段界限, 段属性
40     dw    %2 & 0xFFFF                         ; 段界限1
41     dw    %1 & 0xFFFF                         ; 段基址1
42     db    (%1 >> 16) & 0xFF                   ; 段基址2
43     dw    ((%2 >> 8) & 0xF00) | (%3 & 0xF0FF) ; 属性1 + 段界限2 + 属性2
44     db    (%1 >> 24) & 0xFF                   ; 段基址3
45 %endmacro                                     ; 共 8 字节
46
47 ;Gate
48 ; usage : Gate Selector, Offset, DCount, Attr
49 ;         Selector : dw
50 ;          Offset   : dd
51 ;          DCount   : db
52 ;          Attr       : db
53 %macro Gate 4
54     dw        (%2 & 0xFFFF)                        ; pianyidizhi1
55     dw        %1                                    ; xuanzezi
56     dw        (%3 & 0x1F) | ((%4 << 8) & 0xFF00)    ; shu xing
57     dw        ((%2 >> 16) & 0xFFFF)                ; pianyidizhi2
58 %endmacro

18-2节的loader.asm例子如下:

  1 %include "inc.asm"
  2
  3 org 0x9000
  4
  5 jmp ENTRY_SEGMENT
  6
  7 [section .gdt]
  8 ; GDT definition
  9 ;                                 段基址,       段界限,       段属性
 10 GDT_ENTRY       :     Descriptor    0,            0,           0
 11 CODE32_DESC     :     Descriptor    0,    Code32SegLen  - 1,   DA_C + DA_32 + DA_DPL0
 12 VIDEO_DESC      :     Descriptor 0xB8000,       0x07FFF,       DA_DRWA + DA_32 + DA_DPL0
 13 DATA32_DESC     :     Descriptor    0,    Data32SegLen - 1,    DA_DR + DA_32 + DA_DPL0
 14 STACK32_DESC    :     Descriptor    0,      TopOfStack32,      DA_DRW + DA_32  + DA_DPL0
 15 FUNCTION_DESC   :     Descriptor    0,   FunctionSegLen - 1,   DA_C + DA_32 + DA_DPL0
 16 TASK_A_LDT_DESC :     Descriptor    0,      TaskALdtLen - 1,   DA_LDT + DA_DPL0
 17 ; GDT end
 18
 19 GdtLen    equ   $ - GDT_ENTRY
 20
 21 GdtPtr:
 22           dw   GdtLen - 1
 23           dd   0
 24
 25
 26 ; GDT Selector
 27
 28 Code32Selector    equ (0x0001 << 3) + SA_TIG + SA_RPL0
 29 VideoSelector     equ (0x0002 << 3) + SA_TIG + SA_RPL0
 30 Data32Selector    equ (0x0003 << 3) + SA_TIG + SA_RPL0
 31 Stack32Selector   equ (0x0004 << 3) + SA_TIG + SA_RPL0
 32 FunctionSelector  equ (0x0005 << 3) + SA_TIG + SA_RPL0
 33 TaskALdtSelector  equ (0x0006 << 3) + SA_TIG + SA_RPL0
 34 ; end of [section .gdt]
 35
 36 TopOfStack16    equ  0x7c00
 37
 38 [section .s16]
 39 [bits 16]
 40 ENTRY_SEGMENT:
 41     mov ax, cs
 42     mov ds, ax
 43     mov es, ax
 44     mov ss, ax
 45     mov sp, TopOfStack16
 46
 47     ; initialize GDT for 32 bits code segment
 48     mov esi, CODE32_SEGMENT
 49     mov edi, CODE32_DESC
 50
 51     call InitDescItem
 52
 53     mov esi, DATA32_SEGMENT
 54     mov edi, DATA32_DESC
 55
 56     call InitDescItem
 57
 58     mov esi, STACK32_SEGMENT
 59     mov edi, STACK32_DESC
 60
 61     call InitDescItem
 62
 63     mov esi, FUNCTION_SEGMENT
 64     mov edi, FUNCTION_DESC
 65
 66     call InitDescItem
 67
 68     mov esi, TASK_A_LDT_ENTRY
 69     mov edi, TASK_A_LDT_DESC
 70
 71     call InitDescItem
 72
 73     mov esi, TASK_A_DATA32_SEGMENT
 74     mov edi, TASK_A_DATA32_DESC
 75
 76     call InitDescItem
 77
 78     mov esi, TASK_A_CODE32_SEGMENT
 79     mov edi, TASK_A_CODE32_DESC
 80
 81     call InitDescItem
 82
 83     mov esi, TASK_A_STACK32_SEGMENT
 84     mov edi, TASK_A_STACK32_DESC
 85
 86     call InitDescItem
 87
 88     ; initialize GDT pointer struct
 89     mov eax, 0
 90     mov ax, ds
 91     shl eax, 4
 92     add eax, GDT_ENTRY
 93     mov dword [GdtPtr + 2], eax
 94
 95     ; 1. load GDT
 96     lgdt [GdtPtr]
 97
 98     ; 2. close interrupt
 99     cli
100
101     ; 3. open A20
102     in al, 0x92
103     or al, 00000010b
104     out 0x92, al
105
106     ; 4. enter protect mode
107     mov eax, cr0
108     or eax, 0x01
109     mov cr0, eax
110
111     ; 5. jump to 32 bits code
112     jmp dword Code32Selector : 0
113
114
115 ; esi    --> code segment label
116 ; edi    --> descriptor label
117 InitDescItem:
118     push eax
119
120     mov eax, 0
121     mov ax, cs
122     shl eax, 4
123     add eax, esi
124     mov word [edi + 2], ax
125     shr eax, 16
126     mov byte [edi + 4], al
127     mov byte [edi + 7], ah
128
129     pop eax
130
131     ret
132
133 [section .dat]
134 [bits 32]
135 DATA32_SEGMENT:
136     DTOS               db   "D.T.OS!", 0
137     DTOS_OFFSET        equ  DTOS - $$
138
139 Data32SegLen   equ  $ - DATA32_SEGMENT
140
141
142 [section .s32]
143 [bits 32]
144 CODE32_SEGMENT:
145     mov ax, VideoSelector
146     mov gs, ax
147
148     mov ax, Data32Selector
149     mov ds, ax
150
151     mov ax, Stack32Selector
152     mov ss, ax
153
154     mov eax, TopOfStack32
155     mov esp, eax
156
157     mov ebp, DTOS_OFFSET
158     mov bx, 0x0c
159     mov dh, 12
160     mov dl, 33
161
162     call FunctionSelector : PrintString
163
164     mov ax, TaskALdtSelector
165
166     lldt ax
167
168     push TaskAStack32Selector
169     push TaskATopOfStack32
170     push TaskACode32Selector
171     push 0
172     retf
173
174     jmp $
175
176 Code32SegLen    equ    $ - CODE32_SEGMENT
177
178 [section .gs]
179 [bits 32]
180 STACK32_SEGMENT:
181     times 1024 * 4 db 0
182
183 Stack32SegLen   equ $ - STACK32_SEGMENT
184 TopOfStack32    equ Stack32SegLen - 1
185
186
187 ; ======================================
188 ;
189 ;      Global Function Segment
190 ;
191 ; ======================================
192
193 [section .func]
194 [bits 32]
195 FUNCTION_SEGMENT:
196
197 ; ds:ebp     -->    string  address
198 ; bx         -->    attribute
199 ; dx         -->    dh : row, dl : col
200 PrintStringFunc:
201     push ebp
202     push eax
203     push edi
204     push cx
205     push dx
206
207 print:
208     mov cl, [ds:ebp]
209     cmp cl, 0
210     je end
211     mov eax, 80
212     mul dh
213     add al, dl
214     shl eax, 1
215     mov edi, eax
216     mov ah, bl
217     mov al, cl
218     mov [gs:edi], ax
219     inc ebp
220     inc dl
221     jmp print
222
223 end:
224     pop dx
225     pop cx
226     pop edi
227     pop eax
228     pop ebp
229
230     retf
231
232 PrintString       equ    PrintStringFunc - $$
233
234 FunctionSegLen    equ    $ - FUNCTION_SEGMENT
235
236 ; ==================================
237 ;
238 ;        Task A Code Segment
239 ;
240 ;===================================
241 [section .task-a-ldt]
242 ; Task A LDT definition
243 ;                                ???ù?·         ?????T                ??ê?D?
244
245 TASK_A_LDT_ENTRY:
246 TASK_A_CODE32_DESC  : Descriptor   0,    TaskACode32SegLen - 1,  DA_C + DA_32 + DA_DPL3
247 TASK_A_DATA32_DESC  : Descriptor   0,    TaskAData32SegLen - 1,  DA_DR + DA_32 + DA_DPL3
248 TASK_A_STACK32_DESC : Descriptor   0,    TaskAStack32SegLen - 1, DA_DRW + DA_32 + DA_DPL3
249
250 TaskALdtLen        equ   $ - TASK_A_LDT_ENTRY
251
252 ; Task A LDT  Selector
253 TaskACode32Selector        equ  (0x0000 << 3) + SA_TIL + SA_RPL3
254 TaskAData32Selector     equ     (0x0001 << 3) + SA_TIL + SA_RPL3
255 TaskAStack32Selector    equ  (0x0002 << 3) + SA_TIL + SA_RPL3
256
257 [section .task-a-dat]
258 [bits 32]
259 TASK_A_DATA32_SEGMENT:
260     TASK_A_STRING        db   "This is Task A", 0
261     TASK_A_STRING_OFFSET    equ     TASK_A_STRING - $$
262
263 TaskAData32SegLen    equ $ - TASK_A_DATA32_SEGMENT
264
265 [section .task-a-gs]
266 [bits 32]
267 TASK_A_STACK32_SEGMENT:
268     times 1024 db 0
269
270 TaskAStack32SegLen    equ     $ - TASK_A_STACK32_SEGMENT
271 TaskATopOfStack32    equ     TaskAStack32SegLen - 1
272
273 [section .task-a-s32]
274 [bits 32]
275 TASK_A_CODE32_SEGMENT:
276     mov ax, TaskAData32Selector
277     mov ds, ax
278
279     jmp $
280
281
282 TaskACode32SegLen   equ  $ - TASK_A_CODE32_SEGMENT

第10-16行我们定义的段描述符特权级都是0,处理器从实模式跳转到保护模式后进入的是核心特权级0,进入32位的保护模式后首先执行的是144行的程序,我们首先将一些段选择子放在段寄存器中,157-162行调用了函数进行打印,这个FUNCTION_SEGMENT段也是在特权级0,所以这时候的打印不涉及特权级的转移。

164-166行将任务段的选择子加载进CPU的特殊寄存器中,168-170将任务段的栈段选择子、栈顶地址、任务段的代码段选择子压入高特权级的栈中,第171行压入的0指的是偏移地址,第172行的retf远跳转返回的作用是使处理器从核心特权级0跳转到普通特权级3。跳转的时候处理器会自动的在核心态的栈中加载我们刚刚存进去的值到相应的寄存器中,然后程序就到了275行的任务段中的代码段执行。

为了单步执行我们先使用如下命令对loader可执行程序进行反编译:

ndisasm -b 32 -o 0x9000 loader > loader.txt

-b 32是以32位的方式进行反编译。

在反编译得到文件中我们找到lldt所在的位置,断点就打在这里:

启动bochs,使用break 0x915D打上断点。

输入c执行到断点处,结果如下:

可以看到下一条指令就是 lldt ax,继续单步执行:

单步执行并使用sreg查看寄存器信息,可以看到cs中的值是0x0008,可知最后两位是00,这时处于核心特权级0。

继续单步执行:

retf执行完之后再次使用retf查看寄存器的值,可以看到cs的之变成了0x0007,最后两位是11,这说明特权级变为了3。

继续单步执行:

程序转移到了276行的地方。

原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9782418.html

时间: 2024-10-15 22:32:34

第十八课 特权级转移(上)的相关文章

NeHe OpenGL教程 第三十八课:资源文件

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十八课:资源文件 从资源文件中载入图像: 如何把图像数据保存到*.exe程序中,使用Windows的资源文件吧,它既简单又实用. 欢迎来到NeHe教程第38课.离上节课的写作已经有些时日了,加上写了一整天的code,也许笔头已经

NeHe OpenGL教程 第二十八课:贝塞尔曲面

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( [email protected] ) 这篇教程旨在介绍贝塞尔曲面,希望有比我更

NeHe OpenGL教程 第十八课:二次几何体

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第十八课:二次几何体 二次几何体: 利用二次几何体,你可以很容易的创建球,圆盘,圆柱和圆锥. 二次曲面是一种画复合对象的方法,这种方法通常并不需要很多的三角形.我们将要使用第七课的代码.我们将要增加7个变量以及修改纹理以增加一些变化

斯坦福第十八课:应用实例:图片文字识别(Application Example: Photo OCR)

18.1  问题描述和流程图 18.2  滑动窗口 18.3  获取大量数据和人工数据 18.4  上限分析:哪部分管道的接下去做 18.1  问题描述和流程图 图像文字识别应用所作的事是,从一张给定的图片中识别文字.这比从一份扫描文档中 识别文字要复杂的多. 为了完成这样的工作,需要采取如下步骤: 为了完成这样的工作,需要采取如下步骤: 1. 文字侦测(Text detection)——将图片上的文字与其他环境对象分离开来 2. 字符切分(Character segmentation)——将文

jmp &amp;&amp; call &amp;&amp; ret 特权级转移 &amp; 进程调度

①jmp是不负责任的调度,不保存任何信息,不考虑会回头.跳过去就什么也不管了.②call,保存eip等,以便程序重新跳回.ret是call的逆过程,是回头的过程.这都是cpu固有指令,因此要保存的信息,不用我们自己保存.我们直接使用指令即可③同一任务内特权级转移,跟 ②差不多,不过要准备个tss,并加载它,然后call 门一下就行了.④进程调度,进程的界限是我们人为加上的,cpu并不知道进程要切换了,也没有特定的进程指令.因此进程的状态需要我们自己保存.上面的关系好像是在盖房子,越盖越高,越盖越

第三十八课、Qt中的事件处理(上)

一.图形界面应用程序的消息处理模型 二.Qt的事件处理 1.Qt平台将系统产生的消息转换为Qt事件(每一个系统消息对象Qt平台的一个事件) (1).Qt事件是一个QEvent的对象 (2).Qt事件用于描述程序内部或者外部发生的动作 (3).任意的QObject对象都具备事件处理的能力 2.GUI应用程序的事件处理方式 (1).Qt事件产生后立即被分发到QWidget对象 (2).QWidget中的event(QEvent*)进行事件处理 (3).event()根据事件类型调用不同的事件处理函数

第五十八课、自定义模型类(上)------------------狄泰软件学院

 一.自定义模型类 1.QStandardItemModel是一个通用的模型类 (1).能够以任意的方式组织数据(线程.非线性) (2).数据组织的基本单位为数据项(QStandardItem) (3).每一个数据项能够存储多个具体数据(附加数据角色) (4).每一个数据项能够对数据状态进行控制(可编辑.可选...) 2.Qt中的通用模型类QStandardItemModel (1).QStandardItemModel继承自抽象的模型类QAbstractItemModel (2).QStand

OpenGL教程翻译 第十八课 漫反射光(Diffuse Lighting)

OpenGL教程翻译 第十七课 环境光(Ambient Lighting) 原文地址:http://ogldev.atspace.co.uk/(源码请从原文主页下载) Background 环境光和漫反射光的主要不同是,漫反射光的计算需要依靠光线方向而环境光完全忽略了它!当只有环境光时整个场景被均等照亮.漫反射光会使物体面对光的部分比背对光的部分更加明亮. 此外漫反射光还增加了一点新的计算,光线的入射角决定了表面的亮度.通过下面的图片来演示这个概念: 让我们假设两条光线的强度是一样的,而唯一不一

第三十八课:动画引擎的实现

本课将通过源码分析的形式,来教大家如何实现一个动画引擎的模块. 我们先来看一个使用CSS3实现动画倒带的例子: .animate {    //这个animate类名加在上面的那个方块元素中,这个类名也可以是其他名字,比如:.move,只要设置的是那个方块元素就OK了. animation-duration:3s; animation-name:cycle; animation-iteration-count:2;    //动画播放的次数 animation-direction: altern