天天看點

堆棧基指針

What is the difference between token bucket and leaky bucket algorithms?

Samples: 192K of event 'cpu-clock', 4000 Hz, Event count (approx.): 48187750000

Percent│ ◆

│ /root/.debug/.build-id/80/6c9856a2fdbd570dd869f2b216392efaece1b3/elf: 檔案格式 elf64-x86-64 ▒

│ ▒

│ Disassembly of section .text: ▒

│ 000000000040052d <main>: ▒

│ main(): ▒

│ #include <stdio.h> ▒

│ int main(void) ▒

│ { ▒

│ push %rbp ;堆棧基指針 将寄存器rbp的值推入堆棧,現在rsp的值是堆棧新頂部的記憶體位址 ▒

│ mov %rsp,%rbp ;堆棧頂指針 将堆棧指針rsp的值複制到基指針rbp -> rbp和rsp現在都指向堆棧的頂部 ▒

│ sub $0x10,%rsp ▒

│ unsigned i = 10; ▒

│ movl $0xa,-0x4(%rbp) ;movb(8位)、movw(16位)、movl(32位)、movq(64位) ▒

│ unsigned ii = i - 100; ▒

│ mov -0x4(%rbp),%eax ;累加寄存器 ▒

│ sub $0x64,%eax ▒

│ mov %eax,-0x8(%rbp) ▒

│ int iii = -90; ▒

│ movl $0xffffffa6,-0xc(%rbp) ▒

│ printf("%d,%d,%d", i, ii, iii); ▒

│ mov -0xc(%rbp),%ecx ;計數寄存器 ▒

│ mov -0x8(%rbp),%edx ;資料寄存器 ▒

│ mov -0x4(%rbp),%eax ▒

│ mov %eax,%esi ;變址寄存器 ▒

│ mov $0x400610,%edi ▒

│ mov $0x0,%eax ▒

│ → callq printf@plt ▒

│ while (1 < 11) ▒

│ { ▒

│ printf("%d", ii); ▒

28.37 │39: mov -0x8(%rbp),%eax ▒

9.28 │ mov %eax,%esi ▒

0.18 │ mov $0x400619,%edi ▒

17.86 │ → callq printf@plt ▒

│ } ▒

44.31 │ ↑ jmp 39 ▒

Samples: 62K of event 'cpu-clock', 4000 Hz, Event count (approx.): 15607500000

f /home/hdp/workbench/perfUcan/a.out [Percent: local period]

Percent│ {

10.54 │ push %rbp

5.12 │ mov %rsp,%rbp

0.31 │ sub $0x20,%rsp

│ int i = 6;

7.13 │ movl $0x6,-0x4(%rbp)

│ int j = 10;

23.57 │ movl $0xa,-0x8(%rbp)

│ unsigned k = 10;

9.46 │ movl $0xa,-0xc(%rbp)

│ int ii = -6;

4.03 │ movl $0xfffffffa,-0x10(%rbp)

│ int jj = -10;

3.10 │ movl $0xfffffff6,-0x14(%rbp)

│ int n = -110;

5.43 │ movl $0xffffff92,-0x18(%rbp)

│ printf("hi");

3.26 │ mov $0x400630,%edi

0.16 │ mov $0x0,%eax

0.78 │ → callq printf@plt

│ return 0;

13.80 │ mov $0x0,%eax

│ }

1.09 │ leaveq

12.25 │ ← retq

https://zhuanlan.zhihu.com/p/55896356

函數的第一行涉及rbp和rsp;這些是專用寄存器。

rbp是指向目前棧桢底部的基指針,rsp是指向目前棧桢頂部的堆棧指針。

(譯者注:在很多翻譯過來的書上,有些地方将Stack翻譯為棧桢,有的地方叫堆棧,

隻要知道這裡的堆棧是指Stack,Heap沒關系就好)

rbp = memory address of the base of the prev stack frame

rsp = memory address of the top of the stack

指針寄存器

SP(stack pointer)

BP(base pointer)

堆棧的記憶體位址越來越低,即向位址小的地方增長。

基指針或幀指針。它指向目前運作的函數的棧桢中的一個固定位置,并為通路函數參數和本地變量提供一個穩定的參考點(基)

{

MOV 指令将源操作數複制到目的操作數。作為資料傳送(data transfer)指令,它幾乎用在所有程式中。在它的基本格式中,第一個操作數是目的操作數,第二個操作數是源操作數:

MOV destination,source

其中,目的操作數的内容會發生改變,而源操作數不會改變。這種資料從右到左的移動與 C++ 或 Java 中的指派語句相似:

dest = source;

在幾乎所有的彙編語言指令中,左邊的操作數是目标操作數,而右邊的操作數是源操作數。隻要按照如下原則,MOV 指令使用操作數是非常靈活的。

兩個操作數必須是同樣的大小。

兩個操作數不能同時為記憶體操作數。

指令指針寄存器(IP、EIP 或 RIP)不能作為目标操作數。

}

EAX - 累加器寄存器

EBX - 基礎寄存器

ECX - 計數器寄存器

EDX - 資料寄存器

ESI - 源指針

EDI - 目的地指針

EBP - 基本指針

ESP - 堆棧指針

EAX - Accumulator Register

EBX - Base Register

ECX - Counter Register

EDX - Data Register

ESI - Source Index

EDI - Destination Index

EBP - Base Pointer

ESP - Stack Pointer

在CPU中,有八個通用寄存器

ax (add,代表相加,累加的意思)累加寄存器

bx (base,代表基位址,存放位址的寄存器) 基址寄存器

cx (count,個數,代表統計的意思)計數寄存器

dx (data,資料) 資料寄存器

SI (source) 源寄存器,存放源位址的内容的寄存器

DI (Dest) 目标寄存器,從源寄存器中memcpy到目标寄存器中

BP (base Point) 堆棧,了解為棧底指針,每次在棧中移動資料,出棧進棧,都會更新.記錄的是目前的棧底

SP () 堆棧棧頂指針.

16位彙編第一講簡介

32位彙編第一講x86和8086的差別,以及OllyDbg調試器的使用

一丶32位(x86也稱為80386)與8086(16位)彙編的差別

1.寄存器的改變

  AX 變為 EAX 可以這樣想,16位通用寄存器前邊都加個E開頭

例如:

  

EAX EBX ECX EDX ESI EDI ESP EBP ;八個寄存器

EIP EFLAGES ;特殊寄存器

CS ES SS DS GS FS            ;其中GS FS是新增加的寄存器,這些段寄存器,并不是4個位元組(32位的)還是以前16位的

注意在32位下沒有分段的概念的,因為尋址能力是 0- FFFFFFFF ,在當時的inter認為當初的4G已經很厲害了,那是後最好的記憶體才1G,放到現在看

我們感覺4G不夠用了,但也是近幾年才開始用的8G

有分區的概念,比如我們16位彙編中,給代碼分段的時候,順便分了一下區,分區是為了更好的管理代碼的編寫

https://sourceware.org/gdb/current/onlinedocs/gdb/Memory.html

u10進制 x16

(gdb) x/16ub 0x400650

0x400650: 104 105 0 0 1 27 3 59

0x400658: 56 0 0 0 6 0 0 0

(gdb) x/16xb 0x400650

0x400650: 0x68 0x69 0x00 0x00 0x01 0x1b 0x03 0x3b

0x400658: 0x38 0x00 0x00 0x00 0x06 0x00 0x00 0x00

[hdp@cmd ~]$ cat /proc/version

Linux version 3.10.0-1062.4.1.el7.x86_64 ([email protected]) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Fri Oct 18 17:15:30 UTC 2019

[hdp@cmd ~]$ cat /proc/cpuinfo

processor : 0

vendor_id : GenuineIntel

cpu family : 6

model : 79

model name : Intel(R) Xeon(R) CPU E5-2620 v4 @ 2.10GHz

stepping : 1

microcode : 0xffffffff

cpu MHz : 2095.146

cache size : 20480 KB

physical id : 0

siblings : 2

core id : 0

cpu cores : 1

apicid : 0

initial apicid : 0

fpu : yes

fpu_exception : yes

cpuid level : 20

wp : yes

flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ibrs ibpb stibp fsgsbase bmi1 hle avx2 smep bmi2 erms invpcid rtm rdseed adx smap xsaveopt spec_ctrl intel_stibp arch_capabilities

bogomips : 4190.29

clflush size : 64

cache_alignment : 64

address sizes : 44 bits physical, 48 bits virtual

power management:

processor : 1

apicid : 1

initial apicid : 1

[hdp@cmd ~]$

https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/readelf.html

擁有的條件

static PyObject *

rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored))

unsigned long tid = PyThread_get_thread_ident();

if (self->rlock_count > 0 && self->rlock_owner == tid) {

Py_RETURN_TRUE;

}

Py_RETURN_FALSE;

建立

rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)

rlockobject *self;

self = (rlockobject *) type->tp_alloc(type, 0);

if (self != NULL) {

self->in_weakreflist = NULL;

self->rlock_owner = 0;

self->rlock_count = 0;

self->rlock_lock = PyThread_allocate_lock();

if (self->rlock_lock == NULL) {

Py_DECREF(self);

PyErr_SetString(ThreadError, "can't allocate lock");

return NULL;

}

return (PyObject *) self;

lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds)

_PyTime_t timeout;

PyLockStatus r;

if (lock_acquire_parse_args(args, kwds, &timeout) < 0)

return NULL;

r = acquire_timed(self->lock_lock, timeout);

if (r == PY_LOCK_INTR) {

if (r == PY_LOCK_ACQUIRED)

self->locked = 1;

return PyBool_FromLong(r == PY_LOCK_ACQUIRED);

如果多線程的場景下,沒有在一個線程内的 鎖的擷取與釋放的要求,那麼 Rlock的作用 就是否和Lock一樣?

單線程的情況下,lock有的功能點,Rlock也有,反之不成立;

多線程的情況下, 如果有在同一線程内的鎖的釋放或擷取的需求,則用Rlock;

否則,用Lock,因為Rlock的運作邏輯多于Lock,會有更多的資源消耗 性能開銷。