**å¯è¯ºä¾æ¼ä½ç³»**
åå¨å¼è®¡ç®æºç»æï¼ç±CPUåå
åç»æï¼cpuåå
åä¹é´éè¿æ»çº¿è¿æ¥ï¼CPU䏿IPï¼æä»¤å¯åå¨ï¼ï¼16bitçCPUä¸å«IPï¼32bitçå«EIPï¼64bitçå«RIPãæä»¤å¯å卿åå
åçæä¸ååºåã
IPæåå
åä¸çæä»¤åæ¾çä½ç½®å³CSï¼code Segment,ä»£ç æ®µï¼ï¼CPUä»IPæåçå°åååºä¸æ¡æä»¤è¿è¡æ§è¡ï¼ç¶åIP++ï¼æåä¸ä¸æ¡æä»¤ã
**ABI**
Application Binary Interface,ç¨åºä¸CPUçæ¥å£ï¼æ¯æä»¤ç¼ç ï¼è§å®äºä¸æ¡æ±ç¼ä»£ç å¦ä½ç¼ç æCPUæ§è¡çäºè¿å¶æä»¤ã
æä»¤ä½¿ç¨çå¯å卿ä¸å®ç约å®
æä»¤å¯ä»¥ç´æ¥è®¿é®å
å
x86EIPæ¯32bitï¼æåå
å䏿令çå°åï¼EIPæ¯æ¬¡æ§è¡å®åæåä¸ä¸æ¡æä»¤ï¼ä¸ä¸å®æ¯åºå®ç32bitã
###### x86çå¯åå¨
éç¨å¯å卿ï¼
AXï¼Accumulatorç´¯å å¨ï¼
BX åºå°åå¯åå¨ base register
CX 计æ°å¯åå¨ Count register
DX æ°æ®å¯åå¨ Data register
BP å æ åºæé Base Pointer
SI DI ååå¯åå¨ Index register
SP å æ é¡¶æé Stack Pointer
è¿äºå¯åå¨åé¢å E-1åç¼ä¸º32ä½ç³»ç»ä¸çå¯åå¨åç§°ï¼å¦EAXï¼ESI
段å¯åå¨ï¼
CSï¼ä»£ç 段å¯åå¨ Code Segment Register
DS: æ°æ®æ®µå¯åå¨ Data Segment Register
ESãFSãGSï¼éå æ®µå¯åå¨ Extra Segment Register
SS: å æ 段å¯åå¨ Stack Segment Register
CPUå¨åæä»¤æ¶æ ¹æ®cs:eipæ¥å®ä½æä»¤çä½ç½®ã
æ å¿å¯åå¨ï¼ç¨æ¥æ è¯å½åCPUçç¶æ
æä»¤åç¼b,w,l,qåå«è¡¨ç¤º8,16,32,64ä½ï¼å¦
`movl %eax, %edx edx = eax ` register modeå¯åå¨å¯»åï¼ä»¥%å¼å¤´
`movl $0x123, %edx edx = 0x123 ` immediate ç«å³å¯»åï¼ææ°å¼æ¾å°å¯åå¨ä¸
`movl 0x123, $edx edx = *(int32_t*)0x123` direct ç´æ¥å¯»åï¼å°å°å0x123ä¸ç弿¾å°edxä¸
`movl (%ebx), %edx edx = *(int32_t*)ebx` indirect é´æ¥å¯»å,ebxä¸å°åæåç弿¾å°edxä¸
`movl 4(%ebx), %edx edx = *(int32_t*)(ebx+4)` displaced åå寻åï¼å°ebxçå°åå
å¢å 4åï¼åååºè¿ä¸ªå°åä¸å¼æ¾å
¥edx
Linux使ç¨çæ¯AT&Tçæ±ç¼æ ¼å¼ï¼åIntelçæ±ç¼æ ¼å¼ä¸å
`pushl %EAX ` å°å¯åå¨EAXçå¼åå°æ é¡¶ï¼è¯¥æä»¤çä»·äºï¼
`sub $4, %esp` å°espå°åè¿è¡åæ³æä½ï¼æåå æ ä¸ä¸ä¸ªä½ç½®ï¼åä¸çé¿ï¼
`mov %eax, (%esp)`å°eaxä¸ç弿¾å°espå°åæåçå
åä¸
å æ åä¸å¢é¿ï¼ ebpåespä¸èµ·é
对ï¼è¿ä¸¤ä¸ªç以çä½ä¸¤ä¸ªæéï¼æ»æ¯æåæ ç䏿®µç©ºé´ï¼éè¿ä¸æä¿®æ¹è¿ä¸¤ä¸ªæéçæåï¼å½¢æå¤ä¸ªé»è¾çæ 空é´
EBP --> æ åºæé 彿°æ å¸§çæ åº
ESP --> æ é¡¶æé 彿°å æ çæ é¡¶
`pop %eax` åºæ çä»·äºï¼
`mov (%esp), %eax` å°espæåçå
åä¸ç弿¾å
¥eaxä¸
`add $4, %esp` å°espåä¸ç§»å¨ä¸ä¸ªä½ç½®
`call 0x12345678` equal to:
`push %eip` å°å½åCPUæ§è¡çæä»¤å°ååæ ï¼ç¸å½äºå½æ°è¿åç¹
`mov $0x12345678, %eip` å°å°å0x12345678å°åæ¾å
¥eipï¼è®©cpuæ§è¡å®ã
`ret` equal to:
`pop %eip` å¼¹åºå½åæ é¡¶æ¾å°eipä¸ï¼è®©CPUæ§è¡ï¼å³å½æ°è°ç¨åpushå°æ é¡¶çæä»¤ã
ç¼è¯æ±ç¼ï¼
```
int g(int x)
{
return x + 3;
}
int f(int x)
{
return g(x);
}
int main(void)
{
return f(8) + 1;
}
```
`gcc -S -o main.s main.c -m32` //以32bitç¼è¯main.cï¼è¾åºæ±ç¼ä»£ç å°main.sä¸
```
g:
pushl %ebp //å°fçebpä¿åå°æ é¡¶ï¼espæåä¸ä¸ä¸ªä½ç½®
movl %esp, %ebp //å°ebpæåå½åespçä½ç½®ï¼å³å°espå½åææåçå°ååå
¥ebpä¸ï¼å¼å§å½æ°gçæ ç©ºé´
movl 8(%ebp), %eax //å°å½åebp䏿¹ä¸¤ä¸ªä½ç½®å¤çgç忰弿¾å
¥eax
addl $3, %eax //å°æ°å3åeaxä¸çå¼ç¸å ï¼ä¿åå°eaxä¸
popl %ebp //让ebpæåä¿åfçebpçå°åï¼ä¹åespæåäºä¿åçeipæä»¤
ret //让eipæåè¿å
¥gä¹åæä»¤ï¼å³f彿°ä¸çleaveæä»¤
f:
pushl %ebp // å°mainçebpå¼ä¿åå°æ é¡¶ï¼espæåä¸ä¸ä¸ªä½ç½®
movl %esp, %ebp //å°ebpæåå½åespçä½ç½®ï¼æ¤æ¶è¿ä¸ªebpçä½ç½®ä¸æ¹æä¸ä¸ä¸ªæ¹æ³çebpçå°ååè¿å
¥è¯¥æ¹æ³ä¹åä¿åçeipçå°åï¼å
±8个åè
subl $4, %esp //espæåä¸ä¸ä¸ªä½ç½®
movl 8(%ebp), %eax //åå寻åï¼å°ebpçå°åå¢å 8ï¼å³åä¸ç§»å¨ä¸¤ä¸ªä½ç½®ï¼ä¹å°±æ¯ä¼ å
¥è¯¥æ¹æ³çåæ°ç弿¾å
¥eaxä¸
movl %eax, (%esp) //å°eaxä¸ç弿¾å
¥espæåçå
åä¸ï¼å³åå¤å½æ°gçåæ°
call g //å°å½åçeip(æåleave)æ¾å
¥æ é¡¶ï¼å°gå°åèµç»eipå¼å§æ§è¡g
leave
ret
main:
pushl %ebp
movl %esp, %ebp //ebpåespæååä¸ä¸ªä½ç½®ï¼ä¸ä¸ªç©ºæ å¼å§
subl $4, %esp // espåä¸å¢é¿ä¸ä¸ªä½ç½®
movl $8, (%esp) // æ8æ¾å
¥espå½åæåçæ ç©ºé´ä¸
call f //å°å½åçeipï¼æ¤æ¶eipå·²ç»æåä¸é¢addlè¿æ¡æä»¤äºï¼æ¾å
¥æ é ï¼åå°fçå°åæ¾å
¥eipä¸ï¼è®©eipæåfï¼å¼å§æ§è¡
addl $1, %eax
leave
ret
```
64bitç³»ç»ä¸ï¼å¯åå¨ebp为rbpï¼æ å°åæ¯æ¬¡ä¸º8个åèï¼unsigned longï¼
main.s䏿æä»¥.å¼å¤´çè¯å¥æ¯è¿æ¥çè¾
å©ä¿¡æ¯ï¼ä¸ä¼è¢«æ§è¡ï¼å¯ä»¥å¿½ç¥ã
enteræä»¤ï¼ å æ¤è¿ä¸¤æ¡æä»¤è¯´æäºä¸ä¸ªå½æ°è°ç¨çå¼å§
`push %ebp` æå½å卿§è¡çæ åºæéåå
¥æ é¡¶
`mov %esp, %ebp` æ°å¼ä¸ä¸ªç©ºæ ï¼å°ebpæåå½åespä½ç½®ãä¹åèçebpçå¼å·²ç»ä¿åå°äºæ éï¼å æ¤å¯ä»¥å¼å§ä¸ä¸ªæ°ç彿°è°ç¨
leaveæä»¤:
`mov %ebp, %esp` 让espæåå½åebpçæéä½ç½®ï¼ç¸å½äºå½å彿°æ 帧çåºå°å
`pop %ebp` 让ebpæåenteræä»¤è°ç¨æ¶ï¼ä¿åçebpå°åï¼å³è°ç¨å½æ°ä¹åç彿°çåºå°å
ä¾å2ï¼
```
int multi(int x)
{
return x * 3;
}
int add(int x, int y)
{
return multi(x) + y;
}
int main(void)
{
return add(4, 2) + 1;
}
```
æ±ç¼ä»£ç ï¼
```
multi:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %edx
movl %edx, %eax
addl %eax, %eax
addl %edx, %eax
popl %ebp
ret
add:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call multi
movl 12(%ebp), %edx
addl %edx, %eax
leave
ret
main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $2, 4(%esp)
movl $4, (%esp)
call add
addl $1, %eax
leave
ret
```
##### ubuntu 64 bit gcc
`cat /proc/self/maps`访é®procçè¿ç¨çmapæè
`cat /proc//maps`æ¥çæä¸ªè¿ç¨å
·ä½çå
åæ å°å°å
```
edison@aquarius:~$ cat /proc/9793/maps
00400000-00401000 r-xp 00000000 08:06 154592 /media/edison/data/code/linux/LinuxStudy/fun_frame
00600000-00601000 r--p 00000000 08:06 154592 /media/edison/data/code/linux/LinuxStudy/fun_frame
00601000-00602000 rw-p 00001000 08:06 154592 /media/edison/data/code/linux/LinuxStudy/fun_frame
006e4000-00705000 rw-p 00000000 00:00 0 [heap]
7f64f59dc000-7f64f5b9c000 r-xp 00000000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f64f5b9c000-7f64f5d9b000 ---p 001c0000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f64f5d9b000-7f64f5d9f000 r--p 001bf000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f64f5d9f000-7f64f5da1000 rw-p 001c3000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f64f5da1000-7f64f5da5000 rw-p 00000000 00:00 0
7f64f5da5000-7f64f5dcb000 r-xp 00000000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f64f5fa5000-7f64f5fa8000 rw-p 00000000 00:00 0
7f64f5fc8000-7f64f5fca000 rw-p 00000000 00:00 0
7f64f5fca000-7f64f5fcb000 r--p 00025000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f64f5fcb000-7f64f5fcc000 rw-p 00026000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f64f5fcc000-7f64f5fcd000 rw-p 00000000 00:00 0
7ffcdc5a5000-7ffcdc5c6000 rw-p 00000000 00:00 0 [stack]
7ffcdc5ed000-7ffcdc5ef000 r--p 00000000 00:00 0 [vvar]
7ffcdc5ef000-7ffcdc5f1000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
```
On Unbuntu 16.04 64bit gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.2)
`g++ -g -o fun_frame fun_frame.cpp -Wl,-Map,fun_frame.map`
```CPP
int AddFun(int x)
{
int ret = x + 50;
return ret;
}
void TestFun()
{
int value = 8;
AddFun(value);
}
int main()
{
TestFun();
return 0;
}
```
using GDB `disassemble `, output:
```
main
0x0000000000400507 <+0>: push %rbp
0x0000000000400508 <+1>: mov %rsp,%rbp // rbp = rsp = 0x7fffffffdbb0
0x000000000040050b <+4>: callq 0x4004eb
0x0000000000400510 <+9>: mov $0x0,%eax // å°è¿åå¼0æ¾å
¥eax
0x0000000000400515 <+14>: pop %rbp
0x0000000000400516 <+15>: retq
Dump of assembler code for function TestFun():
0x00000000004004eb <+0>: push %rbp
0x00000000004004ec <+1>: mov %rsp,%rbp // rbp = 0x7fffffffdba0
0x00000000004004ef <+4>: sub $0x10,%rsp //å¼è¾16个åèçç©ºé´ rsp = 0x7fffffffdb90
0x00000000004004f3 <+8>: movl $0x8,-0x4(%rbp) // ææ°å8èµå¼ç»4åèå±é¨åé
0x00000000004004fa <+15>: mov -0x4(%rbp),%eax // æ°å8æ¾å°eaxä¸
0x00000000004004fd <+18>: mov %eax,%edi //å°eaxä¸ç弿¾å
¥ediä¸ï¼æ¾å
¥8
0x00000000004004ff <+20>: callq 0x4004d6 // call卿§è¡æ¶ï¼å
å°ä¸ä¸æ¡æä»¤çå°å0x0400504åæ ï¼åå°è°ç¨å½æ°çå°å0x4004d6ç»ripï¼è®©ripæ§è¡è¯¥å½æ°ï¼æ¤æ¶rbpçæé为0x7fffffffdba0ï¼rspçæé为0x7fffffffdb88
0x0000000000400504 <+25>: nop
0x0000000000400505 <+26>: leaveq // espæåebpçå°åï¼å³æ¸
ç©ºå½æ°æ 帧ï¼åå°ä¸ä¸å±å½æ°çebpç弿¾å°ebpå¯åå¨ï¼ç¸å½æpop ebpçä½ç¨
0x0000000000400506 <+27>: retq //å¼¹åºå½åespï¼æ é¡¶ï¼å°åä¸çå
容0x400510ç»ripæ§è¡ï¼rspæé+1 %rbpå½åå¼ä¸º0x7fffffffdb0,%rspçå¼ä¸º0x7fffffffdbb0
Dump of assembler code for function AddFun(int):
0x00000000004004d6 <+0>: push %rbp //å½åæ 顶为ä¸ä¸ä¸ªå½æ°çrbpçå¼ï¼push彿°ä¸ï¼å
对espæé-1ï¼8åèä½ç½®ï¼ï¼åå°ebpç弿¾å
¥æ°çespæåçå°åä¸ï¼æ¤æ¶rspæéå¼ä¸º0x7fffffffdb80ï¼rbpçæéå¼ä¸º0x7fffffffdba0
0x00000000004004d7 <+1>: mov %rsp,%rbp // å°å½årspçå¼ä»ç»rbpå¯åå¨ï¼rbp = rsp = 0x7fffffffdb80ï¼è¿ä¸ªå°åä¸åæ¾çå°±æ¯ä¸ä¸ªå½æ°çebpå¼
0x00000000004004da <+4>: mov %edi,-0x14(%rbp) //å°åæ°ediçå¼8æ¾å
¥å½æ°æ ä¸ï¼å¼è¾äº20个åèç空é´
=> 0x00000000004004dd <+7>: mov -0x14(%rbp),%eax //å°åæ°æ¾å
¥eaxï¼éè¿eax访é®åæ°ï¼è没æéè¿ç´¢å¼æ æéæ¥ä¼ éåæ°
0x00000000004004e0 <+10>: add $0x32,%eax // 对eaxçå¼å 50
0x00000000004004e3 <+13>: mov %eax,-0x4(%rbp) //å°eaxç弿¾å
¥rbp-4ï¼0x7fffffffdb7cï¼çä½ç½®ä¸çå¼ä¸º0x3a
0x00000000004004e6 <+16>: mov -0x4(%rbp),%eax //å°rbp-4çå¼0x3aæ¾å
¥eax
0x00000000004004e9 <+19>: pop %rbp // å°å½åespæåçå
容æ¾å
¥rbpä¸ï¼åå°espæé+1ï¼æ¤æ¶espæåçå°å为0x7fffffffdb88ï¼è¯¥å°åä¸åæ¾çæ¯è°ç¨call彿°ä¹åä¸ä¸æ¡æä»¤çå°åï¼å³: retq //å¼¹åºå½åespï¼æ é¡¶ï¼å°åä¸çå
容0x400504ç»ripæ§è¡ï¼rspæé+1 %rbpå½åå¼ä¸º0x7fffffffdba0,%rspçå¼ä¸º0x7fffffffdb90
```
* æ±ç¼æä»¤åæ¥æ§è¡ `si`
å¨`AddFun(int x)`çå
¥å£å¤æç¹æ¶çè°ç¨å æ
```
(gdb) bt
#0 AddFun (x=8) at fun_frame.cpp:4
#1 0x0000000000400504 in TestFun () at fun_frame.cpp:11
#2 0x0000000000400510 in main () at fun_frame.cpp:16
(gdb) i register
rax 0x8
rdi 0x8
rbp 0x7fffffffdb80
rsp 0x7fffffffdb80 // rsp并没æéç彿°ä¸è¯å¥çæ§è¡æ§è¡èåå°ï¼å§ç»ä½¿ç¨rbp+åç§»éæ¥æ¾å®æ 帧ä¸ç空é´
rip 0x4004dd 0x4004dd
(gdb) x 0x7fffffffdb88 // rbpä¸ä¸ä¸ªä½ç½®çå¼ä¸ºcallä¹åä¸ä¸æ¡æä»¤å°å
0x7fffffffdb88: 0x00400504 // TestFun()ç0400504 <+25>: nop
//宿´æ 空é´å
容
0x7fffffffdba8: 0x400510
0x7fffffffdba0: 0xffffffffffffdbb0
0x7fffffffdb98: 0x4003e0 <_start>
0x7fffffffdb90: 0x400520 <__libc_csu_init>
0x7fffffffdb88: 0x400504
0x7fffffffdb80: 0xffffffffffffdba0 //espæåå°åï¼ä¸ä¸ä¸ªå½æ°AddFun(int)çebpçå°å
(gdb) x 0x7fffffffdba8
0x7fffffffdba8: 0x400510
(gdb) x 0x7fffffffdba0 // 彿°AddFun(int)çebpçå°ååæ¾çmain()彿°çebpå°å
0x7fffffffdba0: 0xffffffffffffdbb0 // å®é
å¼åºè¯¥ä¸º0x7fffffffdbb0
```
``
####å æ ####
å æ æ¯Cè¯è¨ç¨åºè¿è¡æ¶å¿
é¡»çä¸ä¸ªè®°å½è°ç¨è·¯å¾ååæ°ç空é´ãä¿å彿°è°ç¨å°åï¼å±é¨åéï¼å½æ°å
¥åã
gcc -g test.c -o test
objdump -S test -o test.S
GDBæ¥çæ±ç¼ä»£ç `gdb> disassemble /m main`
####䏿####
CPUæå ç§ä¸åçæä»¤æ§è¡çº§å«ï¼é«çº§å«ä¸ï¼ä»£ç å¯ä»¥æ§è¡ç¹ææä»¤ï¼è®¿é®ä»»æç©çå°åï¼å¯¹åºå
æ ¸æï¼ä¸è¬ç±æä½ç³»ç»æ¥æ§è¡ãä½çº§å«ç
åªè½å¨æéçèå´å
æ§è¡ãx86 CPUæ4ä¸ä¸åçæ§è¡çº§å«0-3ï¼Linuxåªä½¿ç¨äºå
¶ä¸ç0å3级ï¼åå«è¡¨ç¤ºå
æ ¸æåç¨æ·æã
CSå¯åå¨çæä½ä¸¤ä½è¡¨æäºå½å代ç çç¹æçº§å«ãCPUæ§è¡çæä»¤ç读åéè¿CS:EIPè¿ä¸¤ä¸ªå¯å卿¥æå®ãCSæ¯ä»£ç æ®µéæ©å¯åå¨ï¼EIPæ¯åç§»éæä»¤å¯åå¨ã
Linuxç³»ç»ä¸0xC0000000以ä¸çå°å空é´åªè½å¨å
æ ¸æè®¿é®ï¼0x00000000-0xbfffffffå¨ä¸¤ç§ç¶æä¸é½å¯ä»¥è®¿é®ã
2^32 = (2^10) * (2^10) * (2^10) * (2^2) = 4GB
å æ¤32ç³»ç»å¯ä»¥å¯»å4Gçå°å空é´
ç¼ç å°±æ¯å¯¹æ¯ä¸ä¸ªç©çåå¨åå
(ä¸ä¸ªåè)åé
ä¸ä¸ªå¯ä¸çå°åå·ç ï¼è¿ä¸ªè¿ç¨åå«åâç¼åâæè
âå°åæ å°â
è¿ç¨çå°å空é´ï¼32bit为4GBï¼æ¯ä¸ªè¿ç¨ä¸ä¸ªãLinuxç³»ç»ä¸ï¼3GB以䏿¯å
æ ¸ç©ºé´ï¼3GB以䏿¯ç¨æ·ç©ºé´
䏿ï¼ä¸ææ¶éè¦ä¿åCPUçæ§è¡ç¶æï¼æ¯ä»ç¨æ·æè¿å
¥å
æ ¸æçä¸»è¦æ¹å¼ï¼ä¾å¦ç¨æ·æç¨åºéè¿ç³»ç»è°ç¨è¿å
¥äºå
æ ¸æï¼è¿ç§æ¹å¼ç§°ä½trapï¼ç³»ç»è°ç¨æ¬è´¨ä¸æ¯ä¸ç§ä¸æï¼æ¤æ¶INTæä»¤ä¼å¨å æ ä¸ä¿åä¸äºå¯åå¨çå¼ï¼ä¾å¦ï¼ç¨æ·æçæ é¡¶å°åã彿¶çç¶æåãCS:EIPçå¼ç
䏿å¼å§æ¶è°ç¨å®SAVE_ALLæ¥ä¿åç°åºï¼ç»æåè°ç¨RESTORE_ALLæ¥æ¢å¤ç°åº
####ç³»ç»è°ç¨
#####为ä»ä¹
æä½ç³»ç»ä¸ºç¨æ·æè¿ç¨æä¾çå硬件设å¤è¿è¡äº¤äºçä¸ç»æ¥å£ï¼ä»è
* æé«ç³»ç»çå®å
¨æ§ï¼
* ç¨æ·ç¨åºä¸éè¦å
³å¿ç¡¬ä»¶ç¼ç¨ï¼
* ä¹ä½¿å¾ç¨æ·ç¨åºæ´å¥½çç§»æ¤ã
#####è¿ç¨
1. interrupt(ex:int 0x80):ä¿åå½åç¨æ·æçcs:eip/ss:esp/eflagså°å
æ ¸çæ ä¸ï¼ç¶åå è½½ä¸ä¸ªä¸æä¿¡å·çå
¥å£å°cs:eipï¼å°å
æ ¸å æ çæéåå
¥ss:espä¸ã
2. SAVE_ALL ä¿åå½åçCPUçç¶æ
3. å¨å
æ ¸æçå æ 䏿§è¡å
æ ¸ä»£ç ï¼å®æç¸å
³ä»»å¡
4. RESTORE_ALL æ¢å¤CPUçæ§è¡ç¶æ
5. iret: pop cs:eip/ss:esp/eflags //åå°ç¨æ·æ
api(åºå½æ°)--> 䏿åé(int 0x80) --> ç³»ç»å
æ ¸å½æ°
system_callæ¯linux䏿æç³»ç»è°ç¨çå
¥å£ç¹ï¼æ¯ä¸ªç³»ç»è°ç¨è³å°æä¸ä¸ªåæ°å³ç±EAXï¼åºå®ä½¿ç¨è¿ä¸ªå¯åå¨ï¼ä¼ éçç³»ç»è°ç¨å·ï¼ç¨æ¥åºåä¸åçç³»ç»è°ç¨ãä¾å¦ï¼fork()æ¥å£ï¼å¨æ§è¡int $0x80ä¹åæeaxçå¼è®¾ç½®ä¸º2ï¼å³_NR_forkï¼
å¯åå¨åæ°ä¼ éï¼
1. æ¯ä¸ªåæ°çé¿åº¦ä¸è½è¶
è¿å¯åå¨çé¿åº¦ï¼å³32bit
2. é¤è¿ç³»ç»è°ç¨å·eaxå¤ï¼åæ°ä¸ªæ°ä¸è½è¶
è¿6个(ebx,ecx, edx, esi, edi, ebp)ï¼å¯ä»¥éè¿å°åæ°æéä¼ éè¿æ¥çæ¹å¼æ¥ä¼ éæ´å¤çåæ°ä¿¡æ¯ã
å
嵿±ç¼çæ¹å¼å®ç°ç³»ç»è°ç¨ï¼
time()æ¥å£å®ç°ï¼
```
time_t tt;
asm volatile(
"mov $0, %%ebx\n\t" //ä¼ å
¥ä¸ä¸ªåæ°0ç»ebx
"mov $0xd, %%eax\n\t" // 设置系ç»è°ç¨å·ä¸º0xdç³»ç»æ¶é´ç³»ç»è°ç¨çå·ç
"int $0x08\n\t" //æ§è¡ä¸æ
"mov %%eax, %0\n\t" //å°ç³»ç»è°ç¨è¿åçæ°æ®æ¾å
¥ç¬¬ä¸ä¸ªåæ°ä¸
:"=m" (tt)
)
printf("%d\n",tt); //æ¤æ¶ttå°±æ¯å½åç³»ç»æ¶é´çå¼
```
ç³»ç»è°ç¨çç¸å
³ä»£ç å¨å
æ ¸çarch/x86/kernel/entry_32.Sä¸ï¼
```
ENTRY(system_call)
......
```
####å
嵿±ç¼####
__asm__(
âæ±ç¼è¯å¥æ¨¡æ¿â // ç¼åéè¦æ§è¡çè¯å¥
âè¾åºé¨åâ // è¯å¥ä¸ç¨å°çè¾åºçåéå®ä¹
âè¾å
¥é¨åâ // è¯å¥ä¸ç¨å°çè¾å
¥åéçå®ä¹
âç ´åæè¿°é¨åâ // åªäºå¯åçå¼è¢«ç ´åï¼å¨è¿é声æ
)
asm ( "statements" : output_regs : input_regs : clobbered_regs);
```
int main()
{
// éè¿åµå
¥æ±ç¼å®ç°ï¼val3 = val1 + val2;
unsigned int val1 = 1;
unsigned int val2 = 2;
unsigned int val3 = 0;
asm volatile ( // ä¸è¦è®©ç¼è¯å¨ä¼å
"movl $0, %%eax\n\t" // %%ç¸å½äºå¤äºä¸ä¸ª%æ¥è½¬ä¹ï¼æ0æ¾å°eaxä¸
"addl %1, %%eax\n\t" // %1 表示è¾å
¥åè¾åºç第äºä¸ªï¼å³ä¸é¢ç"c"(val1)å®ä¹çecx
"addl %2, %%eax\n\t" // %2 表示è¾å
¥åè¾åºç第ä¸ä¸ªï¼å¯¹åºäº"d"(val2)ï¼å³edxä¸çå¼ï¼å³val1+val2
"movl %%eax, %0\n\t" // %0 表示è¾å
¥åè¾åºç第1个ï¼å³å
ååéval3ï¼å°eaxä¸å¼æ¾å
¥å
ååéval3ä¸
:"=m" (val3) // m表示å
ååéï¼=表示æä½æ°æ¯åªåçï¼è¾åºæä½æ°ï¼
:"c"(val1),"d"(val2) // å°val1ç弿¾å°ecxä¸ï¼val2ç弿¾å°edxä¸ï¼âcâ代表ecx
);
return 0;
}
```
PCB process control block
###å
æ ¸å¯å¨
initç®å½ä¸main.c:
```
asmlinkage __visible void __init start_kernel(void)
{
/*
* Need to run as early as possible, to initialize the
* lockdep hash:
*/
lockdep_init();
set_task_stack_end_magic(&init_task); //init_taskå³PCBï¼0å·è¿ç¨å°±æ¯æç»çidleè¿ç¨
smp_setup_processor_id();
debug_objects_early_init();
cgroup_init_early();
local_irq_disable();
early_boot_irqs_disabled = true;
......
ftrace_init();
/* Do the rest non-__init'ed, we're now alive */
rest_init();
}
```
####è¿ç¨ç®¡ç
è¿ç¨ç®¡çtask_structãå
å管çãæä»¶ç³»ç»fs_struct
struct task_struct; // è¿ç¨æè¿°ç»æ
http://codelab.shiyanlou.com/xref/linux-3.18.6/include/linux/sched.h#task_struct
fork()-->Task_RUNNING(就绪ï¼å¹¶æ²¡è¿è¡)-schedule()->Task_RUNNING(è·å¾è°åº¦ï¼çæ£æ§è¡)-do_exit()->Task_Zombie
Task_Interruptable(é»å¡)
åå循ç¯å表
list_head //é常好çä¸ä¸ªååå表å®ç°
ä½¿ç¨ `struct list_head children; /* list of my children */`
```
struct list {
struct list *next, *prev;
};
static inline void
list_init(struct list *list)
{
list->next = list;
list->prev = list;
}
static inline int
list_empty(struct list *list)
{
return list->next == list;
}
static inline void
list_insert(struct list *link, struct list *new_link)
{
new_link->prev = link->prev;
new_link->next = link;
new_link->prev->next = new_link;
new_link->next->prev = new_link;
}
static inline void
list_append(struct list *list, struct list *new_link)
{
list_insert((struct list *)list, new_link);
}
static inline void
list_prepend(struct list *list, struct list *new_link)
{
list_insert(list->next, new_link);
}
static inline void
list_remove(struct list *link)
{
link->prev->next = link->next;
link->next->prev = link->prev;
}
#define list_entry(link, type, member) \
((type *)((char *)(link)-(unsigned long)(&((type *)0)->member)))
#define list_head(list, type, member) \
list_entry((list)->next, type, member)
#define list_tail(list, type, member) \
list_entry((list)->prev, type, member)
#define list_next(elm, member) \
list_entry((elm)->member.next, typeof(*elm), member)
#define list_for_each_entry(pos, list, member) \
for (pos = list_head(list, typeof(*pos), member); \
&pos->member != (list); \
pos = list_next(pos, member))
```
####è¿ç¨å建
```
#include
#include
#include
int main(int argc, char * argv[])
{
int pid;
/* fork another process */
pid = fork();
if (pid < 0)
{
/* error occurred */
fprintf(stderr,"Fork Failed!");
exit(-1);
}
else if (pid == 0)
{
/* child process */
printf("This is Child Process!\n");
}
else //ç¶è¿ç¨ä¸è¿åæ¶ï¼pid为åè¿ç¨çidï¼forkä¼è¿å两次ï¼å æ¤è¿ä¸ªåæ¯ä¹ä¼è¢«æ§è¡
{
/* parent process */
printf("This is Parent Process!\n");
/* parent will wait for the child to complete*/
wait(NULL);
printf("Child Complete!\n");
}
}
```
#####å建æ°è¿ç¨è¿ç¨
forkãvforkåcloneä¸ä¸ªç³»ç»è°ç¨é½å¯ä»¥å建ä¸ä¸ªæ°è¿ç¨ï¼èä¸é½æ¯éè¿è°ç¨*do_fork*æ¥å®ç°è¿ç¨çå建ï¼
Linuxéè¿å¤å¶ç¶è¿ç¨æ¥å建ä¸ä¸ªæ°è¿ç¨ï¼é£ä¹è¿å°±ç»æä»¬çè§£è¿ä¸ä¸ªè¿ç¨æä¾ä¸ä¸ªæ³è±¡çæ¡æ¶ï¼
* å¤å¶ä¸ä¸ªPCBââtask_struct
`err = arch_dup_task_struct(tsk, orig);`
* è¦ç»æ°è¿ç¨åé
ä¸ä¸ªæ°çå
æ ¸å æ
```
ti = alloc_thread_info_node(tsk, node);
tsk->stack = ti;
setup_thread_stack(tsk, orig); //è¿éåªæ¯å¤å¶thread_infoï¼èéå¤å¶å
æ ¸å æ
```
* è¦ä¿®æ¹å¤å¶è¿æ¥çè¿ç¨æ°æ®ï¼æ¯å¦pidãè¿ç¨é¾è¡¨ççé½è¦æ¹æ¹å§ï¼è§copy_processå
é¨ã
ä»ç¨æ·æç代ç çfork();彿°è¿åäºä¸¤æ¬¡ï¼å³å¨ç¶åè¿ç¨ä¸åè¿å䏿¬¡ï¼ç¶è¿ç¨ä»ç³»ç»è°ç¨ä¸è¿åæ¯è¾å®¹æçè§£ï¼åè¿ç¨ä»ç³»ç»è°ç¨ä¸è¿åï¼é£å®å¨ç³»ç»è°ç¨å¤çè¿ç¨ä¸çåªéå¼å§æ§è¡çå¢ï¼è¿å°±æ¶ååè¿ç¨çå
æ ¸å æ æ°æ®ç¶æåtask_structä¸threadè®°å½çspåipçä¸è´æ§é®é¢ï¼è¿æ¯å¨åªé设å®çï¼copy_thread in copy_process
```
*childregs = *current_pt_regs(); //å¤å¶å½åå
æ ¸å æ ç»åè¿ç¨ï¼å³ç¶è¿ç¨è¿å
¥ç³»ç»è°ç¨æ¶ä¿åçå æ ä¿¡æ¯
childregs->ax = 0; //为ä»ä¹åè¿ç¨çforkè¿å0ï¼è¿éå°±æ¯åå ï¼
p->thread.sp = (unsigned long) childregs; //è°åº¦å°åè¿ç¨æ¶çå
æ ¸æ é¡¶
p->thread.ip = (unsigned long) ret_from_fork; //è°åº¦å°åè¿ç¨æ¶çç¬¬ä¸æ¡æä»¤å°åï¼å æ¤å¦æåè¿ç¨å¾å°è°åº¦ï¼éè¿åè¿ç¨çå
æ ¸å æ ä»å
æ ¸æè¿åå°ç¨æ·æï¼å 为ret_from_forkæç»æ§è¡äºsyscall_exit
```
0å·è¿ç¨çPCBæ¯å¨ä»£ç ä¸å好çï¼è1å·è¿ç¨éè¿å¨0å·è¿ç¨ä¸å¤å¶äºä¸ä»½ï¼å¹¶ä½ä¿®æ¹ä»èåå»ºåºæ¥ãLinuxä¸ï¼1å·è¿ç¨æ¯ææç¨æ·æè¿ç¨çç¥å
ï¼0å·è¿ç¨æ¯ææå
æ ¸çº¿ç¨çç¥å
fofork()乿¯ä¸ä¸ªç³»ç»è°ç¨ï¼å¨å®çç³»ç»è°ç¨å½æ°ä¸ï¼å¨å®å
æ ¸å¤ç彿°ä¸å建äºä¸ä¸ªåè¿ç¨
kernel/fork.c
do_fork
####坿§è¡ç¨åº
.c---GCC--->.asm---GAS--->.o---ld--->a.out
æç»å¯æ§è¡æä»¶a.out被å è½½å°å
å䏿§è¡
gcc -E -o hello.cpp hello.c -m32 // 对hello.cè¿è¡é¢å¤ç å
æ¬æ©å±includeç头æä»¶ä»¥åå®å®ä¹
```
gcc -x cpp-output -S -o hello.s hello.cpp -m32 // å°hello.cppç¼è¯ææ±ç¼ä»£ç
gcc -x assembler -c hello.s -o hello.o -m32 //å°hello.sç¼è¯æç®æ æä»¶
gcc -o hello hello.o -m32 //卿龿¥çæhello坿§è¡æä»¶
gcc -o hello.static hello.o -m32 -static //éæé¾æ¥,çææä»¶æ¯è¾å¤§
```
* ELF:Executable and linkable format
* ABI:application binary interface
ELFæä»¶æä¸ç§ï¼
1. å¯éå®ä½æä»¶(relocatable):ä¿åç代ç åéå½çæ°æ®ç¨æ¥åå
¶ä»çobjæä»¶ä¸èµ·å建ä¸ä¸ªå¯æ§è¡æä»¶æè
å
±äº«æä»¶ï¼ å¦.oæä»¶
2. 坿§è¡æä»¶(executable):æåºç³»ç»è°ç¨exec(BA_OS)å¦ä½å建ç¨åºçè¿ç¨æ åï¼å¦.exe
3. å
±äº«ç®æ æä»¶:ä¿åç代ç ååéçæ°æ®ç¨æ¥è¢«ä¸é¢ç两ç§é¾æ¥å¨é¾æ¥ï¼
* 龿¥ç¼è¾å¨ld(SD_CMD),å¯ä»¥åå¯éå®ä½æä»¶æå
±äº«ç®æ æä»¶æ¥å建å
¶ä»çç®æ æä»¶
* 卿龿¥å¨ï¼èåä¸ä¸ªå¯æ§è¡æä»¶åå
¶ä»çå
±äº«ç®æ æä»¶æ¥å建ä¸ä¸ªè¿ç¨æ åã
æ¥çä¸ä¸ªä¸ä¸ªå¯æ§è¡æä»¶çELF头
`readelf -h hello`
ä¸ä¸ªå¯æ§è¡ç¨åºçç»æï¼
```
offset File
0 ELF HEADER
0x100 .Text segment // ä»£ç æ®µ
0xf00 .Data segment // æ°æ®æ®µ
0x1f00 other info
```
ä»£ç æ®µåæ°æ®æ®µçå
容伿 ¹æ®åç§»å°åæ å°å°èæçå
åå°å空é´ï¼èå¨elf头信æ¯ä¸ï¼ç»åºäºç¨åºå
¥å£ç¹çå°åï¼è¿æ¯ç¨åºè¢«å è½½å°å
ååç第ä¸ä¸ªä¸ªæä»¤ã
ç¼è¯çæå
±äº«åºæä»¶
`$ gcc -shared libexample.c -o libexample.so -m32`
*卿龿¥åä¸ºå¯æ§è¡ç¨åºè£
è½½æ¶å¨æé¾æ¥åè¿è¡æ¶å¨æé¾æ¥*ï¼åè
å¾å°ç¨å°
```
int main()
{
printf("This is a Main program!\n");
/* Use Shared Lib */
printf("Calling SharedLibApi() function of libshlibexample.so!\n");
SharedLibApi();
/* Use Dynamical Loading Lib */
void * handle = dlopen("libdllibexample.so",RTLD_NOW); //卿å è½½
if(handle == NULL)
{
printf("Open Lib libdllibexample.so Error:%s\n",dlerror());
return FAILURE;
}
int (*func)(void);
char * error;
func = dlsym(handle,"DynamicalLoadingLibApi");
if((error = dlerror()) != NULL)
{
printf("DynamicalLoadingLibApi not found:%s\n",error);
return FAILURE;
}
printf("Calling DynamicalLoadingLibApi() function of libdllibexample.so!\n");
func();
dlclose(handle);
return SUCCESS;
}
```
注æè¿éåªæä¾libexampleç-Lï¼åºå¯¹åºçæ¥å£å¤´æä»¶æå¨ç®å½ï¼å-lï¼åºåï¼å¦libexample.so廿libå.soçé¨åï¼ï¼å¹¶æ²¡ææä¾libexampleçç¸å
³ä¿¡æ¯ï¼åªæ¯ææäº-ldl(卿å è½½å
±äº«åº)
`$ gcc main.c -o main -L/path/to/your/dir -lexample -ldl -m32`
è¿éè¦è®¾ç½®åºæä»¶çæç´¢ç®å½
`export LD_LIBRARY_PATH=$PWD #å°å½åç®å½å å
¥é»è®¤è·¯å¾ï¼å¦åmainæ¾ä¸å°ä¾èµçåºæä»¶ï¼å½ç¶ä¹å¯ä»¥å°åºæä»¶copyå°é»è®¤è·¯å¾/usr/libä¸ã`
####å¯å¨ä¸ä¸ªç¨åº
å½ä»¤è¡åæ°åshellç¯å¢ï¼ä¸è¬æä»¬æ§è¡ä¸ä¸ªç¨åºçShellç¯å¢ï¼æä»¬çå®éªç´æ¥ä½¿ç¨execveç³»ç»è°ç¨ã
* Shellæ¬èº«ä¸éå¶å½ä»¤è¡åæ°ç个æ°ï¼å½ä»¤è¡åæ°ç个æ°åéäºå½ä»¤èªèº«
* ä¾å¦ï¼int main(int argc, char *argv[])
* åå¦ï¼ int main(int argc, char *argv[], char *envp[]) // envpå
å«shellçç¯å¢åéä¿¡æ¯
* Shellä¼è°ç¨execveå°å½ä»¤è¡åæ°åç¯å¢åæ°ä¼ éç»å¯æ§è¡ç¨åºçmain彿°
`int execve(const char * filename,char * const argv[ ],char * const envp[ ]);`
* åºå½æ°exec*齿¯execveçå°è£
ä¾ç¨
* [sys_execve](http://codelab.shiyanlou.com/xref/linux-3.18.6/fs/exec.c#1604)å
é¨ä¼è§£æå¯æ§è¡æä»¶æ ¼å¼
* do_execve -> do_execve_common -> exec_binprm
search_binary_handler寻æ¾ç¬¦åelfæä»¶æ ¼å¼å¯¹åºçè§£ææ¨¡åï¼å¦ä¸ï¼
```
list_for_each_entry(fmt, &formats, lh) {
if (!try_module_get(fmt->module))
continue;
read_unlock(&binfmt_lock);
bprm->recursion_depth++;
retval = fmt->load_binary(bprm); // å®é
æ§è¡load_elf_binary
read_lock(&binfmt_lock);
```
* 对äºELFæ ¼å¼ç坿§è¡æä»¶fmt->load_binary(bprm);æ§è¡çåºè¯¥æ¯load_elf_binaryå
¶å
鍿¯åELFæä»¶æ ¼å¼è§£æçé¨åéè¦åELFæä»¶æ ¼å¼æ åç»åèµ·æ¥é
读
* Linuxå
æ ¸æ¯å¦ä½æ¯æå¤ç§ä¸åç坿§è¡æä»¶æ ¼å¼çï¼
```
static struct linux_binfmt elf_format = {
.module = THIS_MODULE,
.load_binary = load_elf_binary, // 彿°æé
.load_shlib = load_elf_library,
.core_dump = elf_core_dump,
.min_coredump = ELF_EXEC_PAGESIZE,
};
```
```
static int __init init_elf_binfmt(void)
{
register_binfmt(&elf_format); //å°ä¸é¢å®ä¹ç»ææ³¨åå°å
æ ¸ä¸ï¼ä»èå¯ä»¥æ¾å°è¯¥æ¨¡åæ¥è§£æelfæ ¼å¼
return 0;
}
```
* elf_format å init_elf_binfmtï¼è¿éæ¯ä¸æ¯å°±æ¯è§å¯è
模å¼ä¸çè§å¯è
ï¼
* 坿§è¡æä»¶å¼å§æ§è¡çèµ·ç¹å¨åªéï¼å¦ä½æè½è®©execveç³»ç»è°ç¨è¿åå°ç¨æ·ææ¶æ§è¡æ°ç¨åºï¼
* åºçæ¢¦è¶ ââ éæ¥è¿·ææ¯åºå¨æ¢¦è§äºè´è¶è¿æ¯è´è¶æ¢¦è§äºåºå¨ï¼
* åºå¨ï¼è°ç¨execveç坿§è¡ç¨åºï¼å
¥ç¡ï¼è°ç¨execveé·å
¥å
æ ¸ï¼ï¼éæ¥ï¼ç³»ç»è°ç¨execveè¿åç¨æ·æï¼åç°èªå·±æ¯è´è¶ï¼è¢«execveå è½½ç坿§è¡ç¨åºï¼
* ä¿®æ¹int 0x80åå
¥å
æ ¸å æ çEIP
* load_elf_binary -> start_thread // éè¿ä¿®æ¹å
æ ¸å æ ä¸EIPçå¼ä½ä¸ºæ°ç¨åºçèµ·ç¹
* 卿龿¥çè¿ç¨å
æ ¸åäºä»ä¹ï¼å¯æ§è¡æä»¶ä¾èµç卿龿¥åºï¼å
±äº«åºï¼æ¯ç±è°è´è´£å 载以åå¦ä½éå½å è½½çï¼
#####execveæ§è¡è¿ç¨
`
SYSCALL_DEFINE3(execve,
const char __user *, filename,
const char __user *const __user *, argv,
const char __user *const __user *, envp)`
`int do_execve(struct filename *filename,
const char __user *const __user *__argv,
const char __user *const __user *__envp)`
```
static int do_execve_common(struct filename *filename,
struct user_arg_ptr argv,
struct user_arg_ptr envp)
{
file = do_open_exec(filename);
bprm->file = file;
retval = exec_binprm(bprm);
}
```
å¨load_elf_binaryæ¹æ³ä¸
/* Now we do a little grungy work by mmapping the ELF image into the correct location in memory. */
ELFæä»¶ä¼è¢«é»è®¤æ å°å°0x8048000è¿ä¸ªå°å
对äºéè¦å¨æé¾æ¥ç坿§è¡æä»¶å
å è½½é¾æ¥å¨ldï¼å°å¨æé¾æ¥å¨èµ·ç¹èµç»elf_entryï¼å¦ææ¯éæçç¨åºå°±ç´æ¥ä½¿ç¨elf坿§è¡æä»¶çelf头ä¸å®ä¹çå
¥å£ç¹ï¼æåå¨start_threadçnew_ipå°±æ¯è¿ä¸ªelf_entryçå¼ã
####è¿ç¨åæ¢
è¿ç¨è°åº¦ç触åï¼
* 䏿å¤çè¿ç¨ï¼å
æ¬æ¶é䏿ãI/O䏿ãç³»ç»è°ç¨åå¼å¸¸ï¼ä¸ï¼ç´æ¥è°ç¨schedule()ï¼æè
è¿åç¨æ·ææ¶æ ¹æ®need_reschedæ è®°è°ç¨schedule()ï¼
* å
æ ¸çº¿ç¨å¯ä»¥ç´æ¥è°ç¨schedule()è¿è¡è¿ç¨åæ¢ï¼ä¹å¯ä»¥å¨ä¸æå¤çè¿ç¨ä¸è¿è¡è°åº¦ï¼ä¹å°±æ¯è¯´å
æ ¸çº¿ç¨ä½ä¸ºä¸ç±»çç¹æ®çè¿ç¨å¯ä»¥ä¸»å¨è°åº¦ï¼ä¹å¯ä»¥è¢«å¨è°åº¦ï¼
* ç¨æ·æè¿ç¨æ æ³å®ç°ä¸»å¨è°åº¦ï¼ä»
è½éè¿é·å
¥å
æ ¸æåçæä¸ªæ¶æºç¹è¿è¡è°åº¦ï¼å³å¨ä¸æå¤çè¿ç¨ä¸è¿è¡è°åº¦ã
è¿ç¨ç忢ï¼
* ä¸ºäºæ§å¶è¿ç¨çæ§è¡ï¼å
æ ¸å¿
é¡»æè½åæèµ·æ£å¨CPU䏿§è¡çè¿ç¨ï¼å¹¶æ¢å¤ä»¥åæèµ·çæä¸ªè¿ç¨çæ§è¡ï¼è¿å«åè¿ç¨åæ¢ãä»»å¡åæ¢ãä¸ä¸æåæ¢ï¼
* æèµ·æ£å¨CPU䏿§è¡çè¿ç¨ï¼ä¸ä¸ææ¶ä¿åç°åºæ¯ä¸åçï¼ä¸æå忝å¨åä¸ä¸ªè¿ç¨ä¸ä¸æä¸ï¼åªæ¯ç±ç¨æ·æè½¬åå
æ ¸ææ§è¡ï¼
è¿ç¨ä¸ä¸æå
å«äºè¿ç¨æ§è¡éè¦çææä¿¡æ¯ï¼
* ç¨æ·å°å空é´ï¼å
æ¬ç¨åºä»£ç ï¼æ°æ®ï¼ç¨æ·å æ ç
* æ§å¶ä¿¡æ¯ï¼è¿ç¨æè¿°ç¬¦ï¼å
æ ¸å æ ç
* 硬件ä¸ä¸æï¼æ³¨æä¸æä¹è¦ä¿å硬件ä¸ä¸æåªæ¯ä¿åçæ¹æ³ä¸åï¼
[schedule()](http://codelab.shiyanlou.com/xref/linux-3.18.6/kernel/sched/core.c#2865)彿°éæ©ä¸ä¸ªæ°çè¿ç¨æ¥è¿è¡ï¼å¹¶è°ç¨context_switchè¿è¡ä¸ä¸æç忢ï¼è¿ä¸ªå®è°ç¨switch_toæ¥è¿è¡å
³é®ä¸ä¸æåæ¢:
* next = pick_next_task(rq, prev);//[link](http://codelab.shiyanlou.com/xref/linux-3.18.6/kernel/sched/core.c#pick_next_task)è¿ç¨è°åº¦ç®æ³é½å°è£
è¿ä¸ªå½æ°å
é¨
* context_switch(rq, prev, next);//[link](http://codelab.shiyanlou.com/xref/linux-3.18.6/kernel/sched/core.c#context_switch)è¿ç¨ä¸ä¸æåæ¢
* [switch_to](http://codelab.shiyanlou.com/xref/linux-3.18.6/arch/x86/include/asm/switch_to.h#31)å©ç¨äºprevånextä¸¤ä¸ªåæ°ï¼prevæåå½åè¿ç¨ï¼nextæå被è°åº¦çè¿ç¨
```
#define switch_to(prev, next, last) \
do { \
/* \
* Context-switching clobbers all registers, so we clobber \
* them explicitly, via unused output variables. \
* (EAX and EBP is not listed because EBP is saved/restored \
* explicitly for wchan access and EAX is the return value of \
* __switch_to()) \
*/ \
unsigned long ebx, ecx, edx, esi, edi; \
\
asm volatile("pushfl\n\t" /* save flags */ \
"pushl %%ebp\n\t" /* save EBP */ \ // å
æ ¸å æ ç忢
"movl %%esp,%[prev_sp]\n\t" /* save ESP */ \
"movl %[next_sp],%%esp\n\t" /* restore ESP */ \
"movl $1f,%[prev_ip]\n\t" /* save EIP */ \
"pushl %[next_ip]\n\t" /* restore EIP */ \
__switch_canary \
"jmp __switch_to\n" /* regparm call */ \
"1:\t" \ //å¼å§æ§è¡nextè¿ç¨çç¬¬ä¸æ¡æä»¤
"popl %%ebp\n\t" /* restore EBP */ \
"popfl\n" /* restore flags */ \
\
/* output parameters */ \
: [prev_sp] "=m" (prev->thread.sp), \
[prev_ip] "=m" (prev->thread.ip), \
"=a" (last), \
\
/* clobbered output registers: */ \
"=b" (ebx), "=c" (ecx), "=d" (edx), \
"=S" (esi), "=D" (edi) \
\
__switch_canary_oparam \
\
/* input parameters: */ \
: [next_sp] "m" (next->thread.sp), \
[next_ip] "m" (next->thread.ip), \
\
/* regparm parameters for __switch_to(): */ \
[prev] "a" (prev), \
[next] "d" (next) \
\
__switch_canary_iparam \
\
: /* reloaded segment registers */ \
"memory"); \
} while (0)
```
æä¸è¬çæ
åµï¼æ£å¨è¿è¡çç¨æ·æè¿ç¨X忢å°è¿è¡ç¨æ·æè¿ç¨Yçè¿ç¨
1. æ£å¨è¿è¡çç¨æ·æè¿ç¨X
2. åç䏿ââsave cs:eip/esp/eflags(current) to kernel stack(è¿ç¨Xçå
æ ¸å æ ),then load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack).
3. SAVE_ALL //ä¿åç°åº
4. 䏿å¤çè¿ç¨ä¸æä¸æè¿ååè°ç¨äºschedule()ï¼å
¶ä¸çswitch_toåäºå
³é®çè¿ç¨ä¸ä¸æåæ¢
5. æ å·1ä¹åå¼å§è¿è¡ç¨æ·æè¿ç¨Y(æ¤æ¶æ¯Yçå
æ ¸æå æ ï¼è¿éYæ¾ç»éè¿ä»¥ä¸æ¥éª¤è¢«åæ¢åºå»è¿å æ¤å¯ä»¥ä»æ å·1ç»§ç»æ§è¡)
6. restore_all //æ¢å¤ç°åº
7. iret - pop cs:eip/ss:esp/eflags from kernel stackï¼å°Yè¢«ä¸ææ¶ä¿åå°Yè¿ç¨å
æ ¸å æ å¼¹åºï¼è½¬å°Yçç¨æ·ææ§è¡ï¼
8. ç»§ç»è¿è¡ç¨æ·æè¿ç¨Y
Xï¼ç¨æ·æï¼--ä¿åXå°å
æ ¸å æ --å¼¹åºä¹åä¿åçYçå
æ ¸å æ å°ç¨æ·æå æ ---å¨ç¨æ·ææ§è¡Yçå æ
å ç§ç¹æ®æ
åµ
* éè¿ä¸æå¤çè¿ç¨ä¸çè°åº¦æ¶æºï¼ç¨æ·æè¿ç¨ä¸å
æ ¸çº¿ç¨ä¹é´äºç¸åæ¢åå
æ ¸çº¿ç¨ä¹é´äºç¸åæ¢ï¼ä¸æä¸è¬çæ
åµé常类似ï¼åªæ¯å
æ ¸çº¿ç¨è¿è¡è¿ç¨ä¸åçä¸ææ²¡æè¿ç¨ç¨æ·æåå
æ ¸æç转æ¢ï¼
* å
æ ¸çº¿ç¨ä¸»å¨è°ç¨schedule()ï¼åªæè¿ç¨ä¸ä¸æçåæ¢ï¼æ²¡æåç䏿ä¸ä¸æç忢ï¼ä¸æä¸è¬çæ
åµç®åï¼
* å建åè¿ç¨çç³»ç»è°ç¨å¨åè¿ç¨ä¸çæ§è¡èµ·ç¹åè¿åç¨æ·æï¼å¦forkï¼
* å è½½ä¸ä¸ªæ°ç坿§è¡ç¨åºåè¿åå°ç¨æ·æçæ
åµï¼å¦execveï¼
ææçè¿ç¨å¨3G以ä¸çé¨åæ¯å
±äº«çï¼å³å
æ ¸æçä»£ç æ®µãæ°æ®æ®µï¼å个è¿ç¨æ¯å
±äº«çã
å
æ ¸å¯ä»¥çä½åç§ä¸æå¤çè¿ç¨åå
æ ¸çº¿ç¨çéå
###线ç¨
å¨ä¸ä¸ªè¿ç¨ä¸æ£å¨å建以åå·²ç»å建ç线ç¨å
±äº«ç¸åçå
å空é´/æä»¶æè¿°(file descriptoræä»¶å¥æ)以åå
¶ä»ç³»ç»èµæºï¼ç±äºä¸åå¨ä»»ä½èµæºçæ·è´ï¼å æ¤çº¿ç¨çå建æçæ´é«ã妿ä¸ä¸ªçº¿ç¨ä¿®æ¹äºä¸ä¸ªåéå¼ï¼å
¶ä»ç线ç¨å°ä¼çå°ä¿®æ¹åçå¼ã
Linuxå¹³å°ä¸POSIXæ å线ç¨apiçå®ç°pthreadsç头æä»¶ä¸ºä½æ¯æ ååºä¸æ²¡æï¼éè¦å¨é¾æ¥æ¶å¢å -lpthreadé项
æ¯ä¸ä¸ªçº¿ç¨æä¸ä¸ªå¯ä¸ç线ç¨IDæ è¯ï¼ç±»å为pthread_t
####线ç¨å建
```
/* Create a new thread, starting with execution of START-ROUTINE
getting passed ARG. Creation attributed come from ATTR. The new
handle is stored in *NEWTHREAD. */
extern int pthread_create (pthread_t *__restrict __newthread,
const pthread_attr_t *__restrict __attr,
void *(*__start_routine) (void *),
void *__restrict __arg) __THROWNL __nonnull ((1, 3));
```
线ç¨åå»ºå½æ°ä¼ç«å³è¿åï¼æ4ä¸ªåæ°:
1. ç±»å为pthread_tçæéï¼æ¯ä¸ä¸ªçº¿ç¨æä¸ä¸ªå¯ä¸ç线ç¨IDæ è¯ï¼å建åè¿åå®é
çidå¼
2. ç±»å为pthread_attr_tç线ç¨å±æ§æéï¼å¦æä¼ å
¥NULLï¼å为é»è®¤å¼
3. ç±»å为`void* (*) (void*)`ç彿°æéï¼å³è¿åå¼ååæ°é½ä¸º`void*`ï¼å½çº¿ç¨å建åï¼ä¼ç«å³æ§è¡è¿ä¸ªå½æ°ï¼å½è¿ä¸ªå½æ°æ§è¡ç»æï¼çº¿ç¨ä¹å°±èªå¨ç»æ
4. ç±»å为`void*`ç线ç¨åæ°ï¼è¿ä¸ªåæ°ä¼ä¼ é线ç¨å½æ°
#####ä¼ éåæ°å°çº¿ç¨ä¸
éè¿çº¿ç¨åå»ºå½æ°ç第4ä¸ªåæ°å¯ä»¥å°ä»»æç±»åçåæ°ä¼ éç»çº¿ç¨ãé常å®ä¸ä¸ªéç¨çç»æä½ä¸å
å«çº¿ç¨å½æ°æ³è¦çææåæ°ï¼å¹¶å°è¿ä¸ªç»æä½çæéä½ä¸ºåæ°ä¼ å
¥ãè¿æ ·å¯ä»¥è¾¾å°åä¸ä¸ªçº¿ç¨å½æ°å¯ä»¥è¢«ä¸åç线ç¨å¤ç¨ï¼èåªæ¯æ°æ®ä¸åã
* éè¦æ³¨æä¼ éç»çº¿ç¨çææçåéï¼é½è¦ç¡®ä¿å¨çº¿ç¨ç»æåï¼ä¸ä¼è¢«éæ¾ï¼ç¹å«æ¯ä½¿ç¨å±é¨åéçæ
åµ
```
// 线ç¨å½æ°éç¨åæ°ç»æ
struct char_print_param
{
// print this character
char character;
// print times
int count;
};
// éç¨çº¿ç¨å½æ°
void* char_print(void* info)
{
//å¾å°éè¦çåæ°
char_print_param* p = (char_print_param*)info;
for (int i = 0; i < p->count; ++i) {
cout<character</maps` æ¥çæå®è¿ç¨pidçå
åæ åå
³ç³»
ä¾å¦å¯¹äºæµè¯ç¨åº,`g++ -o mytest main.cpp`ï¼å
¶ä¸ç±äºç³»ç»æ¯64ä½ï¼éè¦ä½¿ç¨longç±»åæ¥ä¿åå°åï¼ä¸è½ç¨int
```
#include
#include
#include
#include
using namespace std;
int main()
{
unsigned long size = 30*1024;
char* p = new char[size];
for(int i = 0; i < size; i++)
{
*(p + i) = 'P';
}
long addr = (long)(p);
cout << "addr of p: " << addr << endl;
string name;
cin >> name;
return 0;
}
```
å¨ç»ç«¯`./mytest`æ§è¡ç¨åºåï¼å
使ç¨å½ä»¤`ps -e | grep mytest`æ¥çæµè¯ç¨åºçpid为8599
çå°ç»æå¦ä¸ï¼
```
$ cat /proc/8599/maps
00400000-00401000 r-xp 00000000 08:06 154834 /code/C++/algorithm/mytest
00601000-00602000 r--p 00001000 08:06 154834 /code/C++/algorithm/mytest
00602000-00603000 rw-p 00002000 08:06 154834 /code/C++/algorithm/mytest
00e6f000-00ea1000 rw-p 00000000 00:00 0 [heap]
7f0f1dba5000-7f0f1dcad000 r-xp 00000000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f0f1dcad000-7f0f1deac000 ---p 00108000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f0f1deac000-7f0f1dead000 r--p 00107000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f0f1dead000-7f0f1deae000 rw-p 00108000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f0f1deae000-7f0f1e06e000 r-xp 00000000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f0f1e06e000-7f0f1e26d000 ---p 001c0000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f0f1e26d000-7f0f1e271000 r--p 001bf000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f0f1e271000-7f0f1e273000 rw-p 001c3000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f0f1e273000-7f0f1e277000 rw-p 00000000 00:00 0
7f0f1e277000-7f0f1e28d000 r-xp 00000000 08:0a 267595 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0f1e28d000-7f0f1e48c000 ---p 00016000 08:0a 267595 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0f1e48c000-7f0f1e48d000 rw-p 00015000 08:0a 267595 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f0f1e48d000-7f0f1e5ff000 r-xp 00000000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f0f1e5ff000-7f0f1e7ff000 ---p 00172000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f0f1e7ff000-7f0f1e809000 r--p 00172000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f0f1e809000-7f0f1e80b000 rw-p 0017c000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f0f1e80b000-7f0f1e80f000 rw-p 00000000 00:00 0
7f0f1e80f000-7f0f1e835000 r-xp 00000000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f0f1ea0d000-7f0f1ea12000 rw-p 00000000 00:00 0
7f0f1ea32000-7f0f1ea34000 rw-p 00000000 00:00 0
7f0f1ea34000-7f0f1ea35000 r--p 00025000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f0f1ea35000-7f0f1ea36000 rw-p 00026000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f0f1ea36000-7f0f1ea37000 rw-p 00000000 00:00 0
7fff71cd6000-7fff71cf7000 rw-p 00000000 00:00 0 [stack]
7fff71deb000-7fff71ded000 r--p 00000000 00:00 0 [vvar]
7fff71ded000-7fff71def000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
```
å
¶ä¸ç¬¬3è¡å举äºå½åç¨åºå¨è¿è¡æ¶çheapå°åèå´ä¸ºï¼
`00e6f000-00ea1000 rw-p 00000000 00:00 0 [heap]`
å¯ä»¥çåºç³»ç»ä¸ºè¯¥ç¨åºé¢ççheapç©ºé´æ200Kï¼æµè¯ç¨åºä¸å®é
使ç¨äº30Kã
å®é
ä¸ç³»ç»ä½¿ç¨äº`/proc//mem`æ å°äºè¿ç¨å¨æ§è¡æ¶çå®é
å
åï¼å æ¤å¯ä»¥éè¿readè¿ä¸ªæä»¶æ¥å°ç¨åºçå
ådumpåºæ¥ï¼ä½æ¯éè¦æ»¡è¶³ä¸¤ä¸ªæ¡ä»¶æè½ä½¿ç¨ç¬¬ä¸æ¹ç¨åºæ·è´å
åä¿¡æ¯ï¼
1. ç®æ ç¨åºå¯ä»¥ä½¿ç¨`ptrace(PTRACE_ATTACH, pid, NULL, NULL) `彿°attachä¸ï¼å 为ä¸ä¸ªè¿ç¨çå
ååªæç¨åºselfå¯ä»¥è®¿é®ï¼gdb乿¯è¿ä¸ªåç
2. 使ç¨rootç¨æ·æ¥æ§è¡è®¿é®æé
å¨stackoverflow䏿¾å°äºä¸é¢çå°ç¨åºï¼ç¨å æ¹å¨ï¼å°ç®æ ç¨åºçheapå
åæ·è´å°ä¸ä¸ªæä»¶ä¸
```
/*************************
sprintf(mem_file_name, "/proc/%d/mem", pid);
mem_fd = open(mem_file_name, O_RDONLY);
ptrace(PTRACE_ATTACH, pid, NULL, NULL);
waitpid(pid, NULL, 0);
lseek(mem_fd, offset, SEEK_SET);
read(mem_fd, buf, _SC_PAGE_SIZE);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
***************************/
#include
#include
#include
#include
#include
#include
void dump_memory_region(FILE* pMemFile, unsigned long start_address, long length, int serverSocket)
{
unsigned long address;
int pageLength = 4096;
unsigned char page[pageLength];
fseeko(pMemFile, start_address, SEEK_SET);
FILE *fp;
if ((fp = fopen("dump_file", "wba")) == NULL)
{
return ;
}
for (address=start_address; address < start_address + length; address += pageLength)
{
fread(&page, 1, pageLength, pMemFile);
if (serverSocket == -1)
{
// write to file
fwrite(&page, 1, pageLength, stdout);
fwrite(&page, 1, pageLength, fp);
}
else
{
send(serverSocket, &page, pageLength, 0);
}
}
fclose(fp);
}
int main(int argc, char **argv) {
if (argc == 2 || argc == 4)
{
int pid = atoi(argv[1]);
long ptraceResult = ptrace(PTRACE_ATTACH, pid, NULL, NULL);
if (ptraceResult < 0)
{
printf("Unable to attach to the pid specified\n");
return 0;
}
wait(pid, NULL, NULL);
char mapsFilename[1024];
sprintf(mapsFilename, "/proc/%s/maps", argv[1]);
FILE* pMapsFile = fopen(mapsFilename, "r");
char memFilename[1024];
sprintf(memFilename, "/proc/%s/mem", argv[1]);
FILE* pMemFile = fopen(memFilename, "r");
int serverSocket = -1;
if (argc == 4)
{
unsigned int port;
int count = sscanf(argv[3], "%d", &port);
if (count == 0)
{
printf("Invalid port specified\n");
return 0;
}
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket == -1)
{
printf("Could not create socket\n");
return 0;
}
struct sockaddr_in serverSocketAddress;
serverSocketAddress.sin_addr.s_addr = inet_addr(argv[2]);
serverSocketAddress.sin_family = AF_INET;
serverSocketAddress.sin_port = htons(port);
if (connect(serverSocket, (struct sockaddr *) &serverSocketAddress, sizeof(serverSocketAddress)) < 0)
{
printf("Could not connect to server\n");
return 0;
}
}
char line[256];
int i = 0;
while (fgets(line, 256, pMapsFile) != NULL)
{
unsigned long start_address;
unsigned long end_address;
sscanf(line, "%08lx-%08lx\n", &start_address, &end_address);
if(i==3)
{
printf("%s: start:%08lx end:%08lx size: %d\n", line, start_address, end_address, end_address - start_address);
dump_memory_region(pMemFile, start_address, end_address - start_address, serverSocket);
}
i++;
}
fclose(pMapsFile);
fclose(pMemFile);
if (serverSocket != -1)
{
close(serverSocket);
}
ptrace(PTRACE_CONT, pid, NULL, NULL);
ptrace(PTRACE_DETACH, pid, NULL, NULL);
}
else
{
printf("%s \n", argv[0]);
printf("%s \n", argv[0]);
exit(0);
}
}
```
ç¼è¯è¯¥ç¨åº`gcc -o dump_data dump.c`使ç¨`$sudo ./dump_data 8599`ï¼å
¶ä¸8599为æ§è¡çmytestç¨åºçpidï¼æ§è¡å®æåå¾å°ç`dump_file`ç大å°ä¸º`204,800 bytes`ï¼ä¸ç³»ç»ç»æµè¯ç¨åºåé
çheap大å°ä¸è´ï¼èæ§è¡mytestç¨åºï¼è¾åº`addr of p: 15207456 `çpçå°å为15207456 (0x00E80C20)ï¼è¿ä¸ªå°åæ¯å¨heapçå°åèå´`00e6f000-00ea1000`å
ãéè¿è®¡ç®åépçå°ååheapçèµ·å§å°åçå·®`0x00E80C20 - 0x00e6f000 = 0x00011c20`å¾å°på¨heapä¸çåç§»ä½ç½®ä¸º0x00011c20ï¼å¨Dumpæä»¶ä¸0x00011c20å¼å§çä½ç½®å¼å§å°±æ¯æµè¯ç¨åºä¸ç»å°åpèµå¼ç`P`å符
```
.....
00011c10: 0000 0000 0000 0000 1178 0000 0000 0000 .........x......
00011c20: 5050 5050 5050 5050 5050 5050 5050 5050 PPPPPPPPPPPPPPPP
00011c30: 5050 5050 5050 5050 5050 5050 5050 5050 PPPPPPPPPPPPPPPP
00011c40: 5050 5050 5050 5050 5050 5050 5050 5050 PPPPPPPPPPPPPPPP
.....
```
说æäºï¼newçå
åä¸ä¸å®å°±æ¯ä»ç³»ç»ç»ç¨åºåé
çheapèµ·å§ä½ç½®å¼å§åé
å
åçï¼èæ¯å¨ä¸é´çæä¸ªä½ç½®ï¼èä¸ä¸ç¥é为ä»ä¹è¿æä¸ªx.
ä¿®æ¹æµè¯ç¨åºç³è¯·30Mçå
å
```
int main()
{
unsigned long size = 30*1024*1024;
char* p = new char[size];
for(int i = 0; i < size; i++)
{
*(p + i) = 'P';
}
long addr = (long)(p);
cout << "addr of p: " << addr << endl;
string name;
cin >> name;
return 0;
}
```
ç¨åºä¸è¾åºçåépçå°å为`addr of p: 139832631033872`,å³0x7F2D524D0010ï¼æ¤æ¶å¨æ¥çç¨åºçproc/pid/mapsçä¿¡æ¯å¦ä¸:
```
00400000-00401000 r-xp 00000000 08:06 154828 /data/code/C++/algorithm/mytest
00601000-00602000 r--p 00001000 08:06 154828 /data/code/C++/algorithm/mytest
00602000-00603000 rw-p 00002000 08:06 154828 /data/code/C++/algorithm/mytest
0093d000-0096f000 rw-p 00000000 00:00 0 [heap]
7f2d524d0000-7f2d542d1000 rw-p 00000000 00:00 0
7f2d542d1000-7f2d543d9000 r-xp 00000000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d543d9000-7f2d545d8000 ---p 00108000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d545d8000-7f2d545d9000 r--p 00107000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d545d9000-7f2d545da000 rw-p 00108000 08:0a 267627 /lib/x86_64-linux-gnu/libm-2.23.so
7f2d545da000-7f2d5479a000 r-xp 00000000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d5479a000-7f2d54999000 ---p 001c0000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d54999000-7f2d5499d000 r--p 001bf000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d5499d000-7f2d5499f000 rw-p 001c3000 08:0a 267557 /lib/x86_64-linux-gnu/libc-2.23.so
7f2d5499f000-7f2d549a3000 rw-p 00000000 00:00 0
7f2d549a3000-7f2d549b9000 r-xp 00000000 08:0a 267595 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d549b9000-7f2d54bb8000 ---p 00016000 08:0a 267595 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d54bb8000-7f2d54bb9000 rw-p 00015000 08:0a 267595 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f2d54bb9000-7f2d54d2b000 r-xp 00000000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d54d2b000-7f2d54f2b000 ---p 00172000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d54f2b000-7f2d54f35000 r--p 00172000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d54f35000-7f2d54f37000 rw-p 0017c000 08:0a 394965 /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.21
7f2d54f37000-7f2d54f3b000 rw-p 00000000 00:00 0
7f2d54f3b000-7f2d54f61000 r-xp 00000000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f2d55139000-7f2d5513e000 rw-p 00000000 00:00 0
7f2d5515e000-7f2d55160000 rw-p 00000000 00:00 0
7f2d55160000-7f2d55161000 r--p 00025000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f2d55161000-7f2d55162000 rw-p 00026000 08:0a 267529 /lib/x86_64-linux-gnu/ld-2.23.so
7f2d55162000-7f2d55163000 rw-p 00000000 00:00 0
7ffdcd8f2000-7ffdcd913000 rw-p 00000000 00:00 0 [stack]
7ffdcd997000-7ffdcd999000 r--p 00000000 00:00 0 [vvar]
7ffdcd999000-7ffdcd99b000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
```
å¯ä»¥åç°heap大大å°è¿æ¯204800åèï¼æ ¹æ¬ä¸å¤å
åç³è¯·ç30M空é´ï¼èåépçå°ååå¨äºç¬¬5è¡å®ä¹ç空é´ï¼è¿ä¸ªå°å空é´çå颿²¡æä»»ä½è¯´æä¿¡æ¯ï¼
`7f2d524d0000-7f2d542d1000 rw-p 00000000 00:00 0 `
è¿ä¸ªå°åèå´è¡¨ç¤ºç大å°ä¸º31461376åèï¼å好满足äº30Må
åçç³è¯·ï¼èèå°page对é½ï¼å®é
å
å大å°è¦ç¨å¾®å¤§äº.C++ä¸ï¼æ 论å¨åªä¸ªå¹³å°ä¸ï¼heapç大尿»æ¯å¨ææ©å¤§çï¼è¿ç¨åOSç³»ç»æ§è¡ç³»ç»è°ç¨è·åè¶³å¤çå
å空é´ãèå¨é¢å®ä¹çheap段大å°å«©å¤æ»¡è¶³ç¨æ·ç³è¯·çå
å大å°éæ±æ¶ï¼å°±ä½¿ç¨é¢è®¢çheapçå°å空é´ãå¨mapsä¿¡æ¯ä¸æ²¡ææè¿°ä¿¡æ¯ç段为å¿åå°åæ å°æ®µï¼å®ä»¬æ¯éè¿`mmap()`使ç¨`MAP_ANONYMOUS`æ è®°å建çï¼å¯¹äºå¿å段ï¼å¯è½æ¯ç¨åºçBSSæ®µï¼æªåå§åçéææ°æ®æ®µï¼é»è®¤å¼é½ä¸º0ï¼ï¼ä¹æå¯è½æ¶ä½¿ç¨malloc彿°ç³è¯·çå
å空é´ã
On most Unix systems, there is a hard limit on how much total memory a process can have. This limit can be queried with the getrlimit system call. The relevant constant is RLIMIT_AS. This limit governs the maximum number of memory pages that can be assigned to a process and directly limits the amount of heap space available. Unfortunately that limit doesn't directly say how much heap you can use. Memory pages are assigned to a process as a result of mmap calls, to hold the program code itself, and for the process' stack. Additionally, this limit is frequently set well in excess of the total memory available to the whole system if you add together physical memory and swap space. So in reality your program will frequently run out of memory before this limit is reached.
Lastly, some versions of Unix over-assign pages. They allow you to allocate a massive number of pages, but only actually find memory for those pages when you write to them. This means your program can be killed for running out of memory even if all the memory allocation calls succeed. The rationale for this is the ability to allocate huge arrays which will only ever be partially used.
You can get the total amount of availabe memory in the sytem by :
```
cat /proc/meminfo | grep CommitLimit
CommitLimit: 3475960 kB
```
This `CommitLimit` is caculated with following formula: `CommitLimit = ('vm.overcommit_ratio' * Physical RAM) + Swap`
It is more typical to fix the size of the heap in dynamic languages with GC. In C and C++, it is a simple matter to ask the OS for more memory, since it is obvious when you need it. As a consequence, the initial heap size matters very little and is just an implementation decision on the part of the allocation library.
In both C and C++ the heap policy is event driven. The compiler does generate heap allocation calls in C++, tho not in C. When the compiler generates a call to an allocator, it is now in the hands of the library because an actual function gets called. That function attempts to allocate from the heap (perhaps something has been freed recently) but if it fails it just calls the OS to get more memory for the process as a whole, and it adds that additional memory to the heap.
If you look in `arch/mips/mm/mmap.c` you'll find there are two ways of laying our memory in Linux, which is chosen depends on the return value of `mmap_is_legacy`, which in turn depends on whether you have enabled an unlimited `stack` (forces the legacy mode) and whether your binary in compiled which the flag `PT_GNU_STACK` (not having this set forces compatibility mode). linuxå¨2.6.7ä¹åå å
¥äºæ°çå
å[å¸å±æ¹å¼](http://lwn.net/Articles/90311/)
æ§çå
åå¸å±æ¹å¼ä¸º:
```
| CODE ---- | HEAP ----------> | MMAP ------> | <-------- STACK |
| 0GB | | 2GB/3 | 2GB |
```
æ°å¢çå
åå¸å±æ¹å¼ä¸ºï¼
```
| CODE ---- | HEAP ----------> | <------------- MMAP | --- STACK |
| 0GB | | 2GB-8MB | 2GB |
```
æ°çå
åå¸å±æ¹å¼ä¸éå¶äºheapç大å°ï¼ä½¿å¾ç¨åºå¯ä»¥ç³è¯·æ´å¤§çå
åã