Any section of code that should be finished by each process that begins it before another process can enter it is called a critical region.
在另一個進程可以進入之前由每個啟動該進程的進程完成的任何程式碼部分稱為臨界區域。
When a process executes in kernel mode, it cannot be arbitrarily suspended and substituted with another process .
當一個行程在核心模式下執行時,它不能被任意掛起並被另一個行程取代。
Therefore on a uniprocessor system, all kernel data structures that are not updated by interrupts or exception handlers are safe for the kernel to access.
因此,在單處理器系統上,所有未由中斷或異常處理程序更新的核心資料結構對於核心存取都是安全的。
Ineffective in multiprocessor system.
在多處理器系統中無效。
Disabling interrupts before entering critical region and restoring the interrupts after leaving the region.
進入臨界區前禁止中斷,離開臨界區後恢復中斷。
Not efficient
效率不高
Not suitable for multiprocessors.
不適合多處理器。
Avoid deadlock.
避免死鎖。
Linux uses signals to notify processes system events .
Linux 使用訊號來通知進程系統事件。
Each event has its own signal number , which is usually referred to by a symbolic constant such as SIGTERM .
每個事件都有自己的訊號編號,通常由符號常數(例如SIGTERM)來引用。
When a process doesn’t define its response to a signal, then kernel will utilize the default action of the signal to handle it.
當進程沒有定義其對訊號的響應時,核心將利用訊號的預設操作來處理它。
Each signal has its own kernel default action.
每個訊號都有自己的核心預設操作。
Terminate the process.
終止該進程。
Core dump and terminate the process
核心轉儲並終止進程
Ignore
忽略
Suspend
暫停
Resume, if it was stopped.
如果已停止,則恢復。
The wait4( ) system call allows a process to wait until one of its children terminates; it returns the process ID ( PID ) of the terminated child.
wait4()系統呼叫允許進程等待,直到其子進程之一終止;它會傳回終止子進程的進程 ID ( PID )。
When executing this system call, the kernel checks whether a child has already terminated.
當執行這個系統呼叫時,核心檢查子進程是否已經終止。
A special zombie process state is introduced to represent terminated processes: a process remains in that state until its parent process executes a wait4( ) system call on it.
引入一種特殊的殭屍進程狀態來表示終止的進程:進程保持在該狀態,直到其父進程對其執行wait4()系統呼叫。
The system call handler extracts data about resource usage from the process descriptor fields .
系統呼叫處理程序從進程描述符欄位中提取有關資源使用情況的資料。
The process descriptor may be released once the data is collected.
一旦收集到數據,就可以釋放進程描述符。
If no child process has already terminated when the wait4( ) system call is executed, the kernel usually puts the process in a wait state until a child terminates.
如果執行wait4()系統呼叫時沒有子程序已經終止,則核心通常會將程序置於等待狀態,直到子程序終止。
Memory Addressing
記憶體尋址
mov es:[eax],ecx ≡ 268908 (larger instruction)
mov es:[eax],ecx == 268908 (更大的指令)
mov [eax],ecx ≡ 8908
mov [eax],ecx ≠ 8908
mov esi, [ebp + 542] ; // uses ss:
mov esi, [ebp + 542] ; // 使用 ss:
mov esi, [esp + 123] ; // uses ss: too
mov esi, [esp + 123] ; // 也使用 ss:
mov eax, [eax + esp] ; // uses ds, because eax is the base
mov eax, [eax + esp] ; // 使用 ds,因為 eax 是基數
// and esp is the scalable register (with scale==1)
// esp 是可擴充暫存器(scale==1)
It's not the property of assembler, but of the processor.
它不是彙編程式的屬性,而是處理器的屬性。
To override it, there's a one byte segment override prefix before the instruction.
要覆蓋它,指令前有一個一字節段覆蓋前綴。
mov es:[eax],ecx ≡ 268908 (larger instruction)
mov es:[eax],ecx == 268908 (更大的指令)
mov [eax],ecx ≡ 8908
mov [eax],ecx ≠ 8908
Memory chips consist of memory cells.
儲存晶片由儲存單元組成。
Each memory cell has a unique address.
每個儲存單元都有一個唯一的位址。
Each memory cell is one byte long.
每個儲存單元都是一個位元組長。
Memory cells may contain instructions or data.
記憶體單元可以包含指令或資料。
![[Pasted image 20241217193403.png]]
![[貼上影像20241217193403.png]]
![[Pasted image 20241217193443.png]]
![[貼上影像20241217193443.png]]
Programs use a memory address to access the content of a memory cell.
程式使用記憶體位址來存取記憶體單元的內容。
The address used by physical memory is different from the address used in a program, even though both are 32 -bit unsigned integers.
實體記憶體使用的位址與程式中使用的位址不同,儘管兩者都是32位元無符號整數。
main()
{
int a,b;
a=3;
b=2;
}
↓
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
andl $-16, %esp
movl undefined, -4(%ebp)
movl $2, -8(%ebp)
leave
ret
The addresses used by a program are divided into several different areas (segments).
程式使用的位址被分成幾個不同的區域(段)。
Items used by a program with similar properties are saved in the same segment.
具有相似屬性的程式所使用的項目保存在同一段中。
Each segment is represented by an 8 -byte Segment Descriptor that describes the segment characteristics.
每個段落由描述段特徵的8位元組段描述符表示。
Segment Descriptors are stored either in the Global Descriptor Table ( GDT ) or in the Local Descriptor Table ( LDT ).
段描述符儲存在全域描述符表( GDT )或本機描述符表( LDT )中。
Usually only one GDT is defined, while each process is permitted to have its own LDT if it needs to create additional segments besides those stored in the GDT .
通常只定義一個GDT ,而每個行程如果需要建立儲存在GDT中的段之外的其他段,則允許擁有自己的LDT 。
The CPU register gdtr contains the address of the GDT in main memory .
CPU暫存器gdtr包含主記憶體中GDT的位址。
The CPU register ldtr contains the address of the LDT of the currently used LDT .
CPU暫存器ldtr包含目前使用的LDT的LDT位址。
32-bit Linear Base Address and Segment Limit are hidden parts.
32 位元線性基底位址和段限制是隱藏部分。
Base field (32): the linear address of the first byte of the segment.
基底字段(32):段的第一個位元組的線性位址。
G granularity flag (1): 0 (byte); 1 (4 K bytes).
G粒度標誌(1):0(位元組); 1(4 K位元組)。
Limit field (20).
限製字段 (20)。
S system flag (1): 0 (system segment); 1 (normal segment).
S系統標誌(1):0(系統段); 1(正常段)。
Type field (4): segment type and its access rights.
類型欄位(4):段類型及其存取權限。
DPL (Descriptor privilege level) (2):
DPL (描述符特權等級)(2):
Segment-present flag
段存在標誌
D / B flag
D / B標誌
Reserved bit
保留位
AVL flag
AVL標誌
2 -bit field of a segment descriptor used to restrict access to the segment.
段描述符的2位元字段,用於限制對段的存取。
It represents the minimal CPU privilege level requested for accessing the segment.
它表示存取該段所請求的最低CPU權限等級。
address =( gdtr / ldtr ) + index *8.
地址=( gdtr / ldtr ) +索引*8。
The first entry of the GDT is always 0.
GDT的第一個條目永遠為 0。
The maximum number of segment descriptors that the GDT can have is 213-1.
GDT可以擁有的最大段描述符數是 213-1。
Segmentation in Linux
Linux 中的分段
The linear addresses associated with such segments all start at 0 and reach the addressing limit of 2 32 __ -1__ . This means that all processes, either in User Mode or in Kernel Mode, may use the same logical addresses.
與此類段相關的線性位址全部從0開始,並達到尋址限制2 32 __ -1__ 。這意味著所有進程,無論是在使用者模式還是在內核模式,都可以使用相同的邏輯位址。
Another important consequence of having all segments start at 0x00000000 is that in Linux, logical addresses coincide with linear addresses ; that is, the value of the Offset field of a logical address always coincides with the value of the corresponding linear address.
讓所有段落都從0x00000000開始的另一個重要後果是,在 Linux 中,邏輯位址與線性位址一致;也就是說,邏輯位址的Offset欄位的值總是與對應的線性位址的值一致。
The Linux __ GDT__
Linux __GDT__
In uniprocessor systems there is only one GDT , while in multiprocessor systems there is one GDT for every CPU in the system.
在單處理器系統中,只有一個GDT ,而在多處理器系統中,系統中的每個CPU都有一個GDT 。
All GDT s are stored in the per- CPU __ __ gdt_page __ __ variable, while the addresses and sizes of the GDT s (used when initializing the gdtr registers) are stored in the per- CPU early_gdt_descr [ ] ][ 2 ][ 3 ] __ __ variable.
所有GDT都儲存在每個CPU __ __ gdt_page __ __ 變數中,而GDT的位址和大小(在初始化gdtr暫存器時使用)儲存在每個CPU Early_gdt_descr [ ] ][ 2 ][ 3 中] __ __ 多變的。
In Linux, the data type of a GDT entry is __struct __ desc_struct .
在 Linux 中, GDT條目的資料型態是 __struct __ desc_struct 。
struct desc_struct {
union {
struct {
unsigned int a;
unsigned int b;
};
struct {
u16 limit0;
u16 base0;
unsigned base1: 8, type: 4, s: 1, dpl: 2, p: 1;
unsigned limit: 4, avl: 1, l: 1, d: 1, g: 1, base2: 8;
};
};
} __attribute__((packed));
As permitted by __ISO C11 __ and for compatibility with other compilers, GCC allows you to define a structure or union that contains, as fields, structures and unions without names.
根據 __ISO C11 __ 的允許以及為了與其他編譯器相容, GCC允許您定義一個結構體或聯合體,其中包含不帶名稱的結構體和聯合體(如字段)。
struct {
int a;
union {
int b;
float c;
};
int d;
} foo;
In Linux, each processor has only one TSS .
在 Linux 中,每個處理器只有一個TSS 。
The virtual address space corresponding to each TSS is a small subset of the liner address space corresponding to the kernel data segment .
每個TSS對應的虛擬位址空間是內核資料段對應的線性位址空間的小子集。
All the TSS s are sequentially stored in the per- CPU init_tss variable
所有TSS都按順序儲存在每個CPU 的init_tss變數中
struct tss_struct { // A TTS
/*
* The hardware state:
*/
struct x86_hw_tss x86_tss;
/*
* The extra 1 is there because the CPU will access an
* additional byte beyond the end of the IO permission
* bitmap. The extra byte must be all 1 bits, and must
* be within the limit.
*/
unsigned long io_bitmap[IO_BITMAP_LONGS + 1];
/*
* .. and then another 0x100 bytes for the emergency kernel stack:
*/
unsigned long stack[64];
} ____cacheline_aligned;
struct x86_hw_tss {
unsigned short back_link, __blh;
unsigned long sp0;
unsigned short ss0, __ss0h;
unsigned long sp1;
/* ss1 caches MSR_IA32_SYSENTER_CS: */
unsigned short ss1, __ss1h;
unsigned long sp2;
unsigned short ss2, __ss2h;
unsigned long __cr3;
unsigned long ip;
unsigned long flags;
unsigned long ax;
unsigned long cx;
unsigned long dx;
unsigned long bx;
unsigned long sp;
unsigned long bp;
unsigned long si;
unsigned long di;
unsigned short es, __esh;
unsigned short cs, __csh;
unsigned short ss, __ssh;
unsigned short ds, __dsh;
unsigned short fs, __fsh;
unsigned short gs, __gsh;
unsigned short ldt, __ldth;
unsigned short trace;
unsigned short io_bitmap_base;
} __attribute__((packed));
void __cpuinit cpu_init(void)
{
int cpu = smp_processor_id();
struct task_struct *curr = current;
struct tss_struct *t = &per_cpu(init_tss, cpu);
...
[set_tss_desc](cpu, t);
...
}
Three Thread-Local Storage ( TLS ) segments: this is a mechanism that allows multithreaded applications to make use of up to three segments containing data local to each thread .
三個執行緒本地儲存 ( TLS ) 段:這是一種允許多執行緒應用程式使用最多三個包含每個執行緒本地資料的段的機制。
The set_thread_area( ) and get_thread_area( ) system calls, respectively, create and release a TLS segment for the executing process.
set_thread_area()和get_thread_area()系統呼叫分別為執行程序建立和釋放TLS段。
Thread-local storage ( TLS ) is a mechanism by which variables are allocated such that there is one instance of the variable per extant thread.
執行緒本地儲存 ( TLS ) 是一種分配變數的機制,使得每個現有執行緒都有一個變數實例。
It requires significant support from the linker ( ld ), dynamic linker ( ld.so ), and system libraries ( libc.so and libpthread.so ), so it is not available everywhere.
它需要連結器 ( ld )、動態連結器 ( ld.so ) 和系統庫( libc.so和libpthread.so )的大力支持,因此並非隨處可用。
__thread int i;
extern __thread struct state s;
static __thread char *p;
The __thread specifier may be used alone, with the extern or __static __ specifiers, but with no other storage class specifier.
__thread說明符可以單獨使用,與extern或 __static __ 說明符一起使用,但不能與其他儲存類別說明符一起使用。
When used with extern or static , ____thread __ must appear immediately after the other storage class specifier.
與extern或static一起使用時,____thread __ 必須緊接在其他儲存類別說明符之後出現。
When the address-of operator is applied to a thread-local variable, it is evaluated at run time and returns the address of the current thread’s instance of that variable.
當取址運算子應用於執行緒局部變數時,它會在執行時進行求值並傳回該變數的目前執行緒實例的位址。
An address so obtained may be used by any thread. When a thread terminates, any pointers to thread-local variables in that thread become invalid.
如此獲得的地址可以被任何線程使用。當執行緒終止時,該執行緒中指向執行緒局部變數的任何指標都會變得無效。
struct data_
{
int id ;
char name[16] ;
} ;
typedef struct data_ sdata ;
static __thread sdata tx ;
Three segments related to Advanced Power Management ( APM ).
與進階電源管理 ( APM ) 相關的三個部分。
Five segments related to Plug and Play ( PnP ) BIOS services .
與即插即用 ( PnP ) BIOS服務相關的五個部分。
A special TSS segment used by the kernel to handle "Double fault " exceptions .
核心用來處理「雙重錯誤」異常的特殊TSS段。
After Linux 2.6.18, there is no default LDT that is shared by ALL processes [ 1 ] .
Linux 2.6.18 之後,沒有所有行程共享的預設LDT [ 1 ] 。
![[Pasted image 20241217195708.png]]
![[貼上影像20241217195708.png]]
In Linux, a process can contain several threads. These threads share the global variables and heap. Each thread has its own stack.
在Linux中,一個行程可以包含多個執行緒。這些執行緒共享全域變數和堆。每個線程都有自己的堆疊。
Per- CPU _ Variables_ _ [_ thinkiii ]
每個CPU _ 變數_ _ [_ thinkiii ]
int e;
__typeof__(e + 1) j; /* the same as declaring int j; */
e = (__typeof__(e)) f; /* the same as casting e = (int) f; */
Given
給定
int T[2]; int i[2];
int T[2]; 整數 i[2];
you can write
你可以寫
__typeof__(i) a; /* all three constructs have the same meaning */
__typeof__(int[2]) a;
__typeof__(T) a;
The behavior of the code is as if you had declared
程式碼的行為就好像您已聲明
int a[2];
A comma expression contains two operands of any type separated by a comma and has left-to-right associativity.
逗號表達式包含由逗號分隔的任何類型的兩個操作數,並且具有從左到右的關聯性。
The left operand is fully evaluated, possibly producing side effects, and its value, if there is one, is discarded.
左操作數被完全求值,可能會產生副作用,並且其值(如果有)將被丟棄。
The right operand is then evaluated.
然後計算正確的操作數。
The type and value of the result of a comma expression are those of its right operand, after the usual unary conversions.
經過通常的一元轉換後,逗號表達式結果的類型和值是其右邊操作數的類型和值。
The following statements are equivalent:
以下語句是等效的:
r = (a,b,...,c);
a; b; r = c;
&(a, b) a, &b
&(a, b) 一、&b
Supplementary Material
補充資料
Each _code segment descriptor _ provides an L bit.
每個_code段描述子_提供一個L位。
This bit allows a code segment to execute 64-bit code or legacy 32-bit code by code segment.
此位元允許代碼段逐個代碼段執行 64 位元代碼或傳統 32 位元代碼。
In IA-32e mode, a segment descriptor table can contain up to 8192 (213) 8-byte descriptors.
在IA-32e模式下,一個段描述符表最多可以包含8192(213)個8位元組描述符。
An entry in the _segment descriptor table _ can be 8 bytes.
_段描述符表_中的條目可以是8位元組。
_System descriptors _ are expanded to 16 bytes (occupying the space of two entries).
_系統描述符_擴展為16位元組(佔用兩個條目的空間)。
Call gate descriptors
呼叫門描述符
IDT gate descriptors
IDT門描述符
LDT and TSS descriptors
LDT和TSS描述符
![[Pasted image 20241217200038.png]]
![[貼上圖片20241217200038.png]]
Previous Materials
以前的材料
![[Pasted image 20241217200240.png]]
![[貼上影像20241217200240.png]]
Segmentation in x84-64 _ [_ Intel -1][ Intel -2]
x84-64 中的分段_ [_ Intel -1][ Intel -2]
The GDTR register holds the base address (64 bits in IA-32e mode) and the 16-bit table limit for the GDT .
GDTR暫存器保存GDT的基底位址( IA-32e模式下為 64 位元)和 16 位元表限制。
In compatibility mode , segmentation functions just as it does using legacy 16-bit or 32-bit protected mode semantics.
在相容模式下,分段功能就像使用傳統的 16 位元或 32 位元保護模式語義一樣。
In 64-bit mode, segmentation is generally (but not completely) disabled, creating a flat 64-bit linear-address space.
在 64 位元模式下,通常(但不是完全)會停用分段,從而創建平坦的 64 位元線性位址空間。
The processor treats the segment base of CS , DS , ES , SS as zero, creating a linear address that is equal to the effective address.
處理器將CS 、 DS 、 ES 、 SS的段基數視為零,從而建立等於有效位址的線性位址。
The FS and GS segments are exceptions.
FS和GS段是例外。
These segment registers (which hold the segment base) can be used as an additional base registers in linear address calculations.
這些段暫存器(保存段基址)可以用作線性位址計算中的附加基址暫存器。
Note that the processor does not perform segment limit checks at runtime in 64-bit mode.
請注意,處理器在 64 位元模式下運作時不會執行段限制檢查。
In IA-32e mode, an Intel 64 processor uses the steps described in x32 architecture to translate a logical address to a linear address.
在IA-32e模式下,Intel 64 處理器使用 x32 架構中所述的步驟將邏輯位址轉換為線性位址。
In 64-bit mode, the offset and base address of the segment are 64-bits instead of 32 bits.
在64位元模式下,段的偏移量和基底位址都是64位元而不是32位元。
![[Pasted image 20241217200511.png]]
![[貼上圖片20241217200511.png]]
The linear address format is also 64 bits wide and is subject to the canonical form requirement.
線性位址格式也是 64 位元寬,並且符合規範形式要求。
Because ES , DS , and SS segment registers are not used in 64-bit mode, their fields (base, limit, and attribute) in segment descriptors _ _ are ignored.
由於ES 、 DS和SS段暫存器在 64 位元模式下不使用,因此它們在段描述符__ 中的欄位(基址、限制和屬性)將被忽略。
Some forms of segment load instructions are also invalid (for example, LDS , POP ES ).
某些形式的段加載指令也是無效的(例如LDS 、 POP ES )。
Address calculations that reference the ES , DS , or SS segments are treated as if the segment base is zero.
引用ES 、 DS或SS段的位址計算被視為段基數為零。
_Code segment descriptors _ and selectors are needed in IA-32e mode to establish the processor’s _operating mode _ and execution privilege-level .
IA-32e模式下需要_代碼段描述符_和選擇器來建立處理器的_操作模式_和執行特權等級。
In IA-32e mode, a code segment descriptor’s DPL is used for execution privilege checks (as in legacy 32-bit mode).
在IA-32e模式中,代碼段描述符的DPL用於執行特權檢查(與傳統 32 位元模式一樣)。
_Code segments _ continue to exist in 64-bit mode even though, for address calculations, the segment base is treated as zero.
_代碼段_繼續存在於 64 位元模式中,即使對於位址計算,段基址被視為零。
Some code-segment ( CS ) descriptor content (the base address and limit fields) is ignored;
一些程式碼段( CS )描述符內容(基底位址和限製字段)被忽略;
The remaining fields function normally (except for the readable bit in the type field).
其餘欄位正常運作(類型欄位中的可讀位元除外)。