CS: APP chapter 3 notes: (variable) stack frame

Mirror from my personal blog

Introduction

Chapter III of CS: APP mainly describes x86_64 assembly in details, which gives a dictionary-like introduction. Nevertheless, the reason why performing this chapter is to give a vivid adhere of chapter V. In this post, I just elaborate a small part introduced by a few of section, that is the runtime stack.Refers to section 3.7~3.10, Stack frame is a major part in procedure calling and manipulation. It stores variables, procedure return address, and any thing may be pushed in according to complier’s flavor.

Big picture

csapp_big.jpg

Stack frame is a memory structure holds procedure. The main function of it is similar to the figure delivered above:

  • control transfer,
  • data transfer,
  • local variables storage.

Notes: Regarding the array and struct or union, however, they are just stored in memory, without being specified whether should be stored in stack or heap file.

Every function refers to a particular interval of stack. As figured in the picture above, stack stores arguments for the calling of next procedure, caller preserve variable in register and memory and return address of the caller, which note as the PC back point.

When we combine control and data together, it will be more complex than before. That is what we refer as variable stack frame, and another miscellaneous.

Control transfer

Control transfer of procedure refers to the function calling. Suppose that function P() wonna call function Q(), once you embody this process, the program should pass some arguments, transfer the PC of %rip to the function Q(), then it go through the instructions in Q(), at last go back to the origin address of %rip when meet ret, which means that return the funtion P().

In x86_64 instruction set, there are three control instructions:

Instruction Description
call Label Procedure call
call *Operand ;;
ret Return from call

The call instruction has a target indicating the address of the instruction where the called procedure starts. Its operand, which is the address, could be direct or indirect. Go back to figure 3.3 could get more details.

Suppose we have details of function below:

Q:
    0x400540    addq %rdi, %rdi
    0x400543    movq %rdi, %rax
    0x400546    ret
    
P:
    0x400560    movq $-1, %rdi
    0x400563    call Q
    0x400568    ret
-------Origin status before call-------
%rsp: 0x7fffffffe888 --> 0x0
%rip: 0x400560
---------------------------------------

-------After execute call--------------
%rsp: 0x7fffffffe880 --> 0x400568(The address of the next ins of call)
%rip: 0x400540 (The atart of Q)
---------------------------------------

------------After ret------------------
%rsp: 0x7fffffffe888 --> 0x0
%rip: 0x400568 (last ins of P)
---------------------------------------

In this simple case, once P call Q, P push its next instruction address as its return address to the stack, then %rip gets start address of Q. When meeting ret, %rip get that address from stack then add address of %rsp according to the size of the cell. It is easy, right?

Data transfer

When passing control to another procedure, we usually pass arguments to the callee one, so as to evaluate the data then get target result. As is mentioned before, we refer %rdi as the 1st argument, %rsi the second, and so on. It is a convention of how x86-64 pass arguments. Marked in details, as below:

Argument sequence Registers notes
1st %rdi few bits portable
2nd %rsi could be accept
3rd %rdx
4th %rcx
5th %r8
6th %r9
more than 6 STORE IN STACK

The point here is, also combine the control transmission, the caller should push it’s variable stored in callee saved registers, set the argument registers into target arguments, after preparing for the function call, the PC go to the target procedure.

As an example:

proc:
    pushq %rbp
    movq %rsp, %rbp  # %rbp is a caller saved register
    add  %edi, %esi  # add %rdi to %rsi
    add  %rsi, %rdx  # ---
    add  %rdx, %rcx  # ---
    sub  %rcx, %r8   # ---
    movq %r8, %rax   # ---
    popq %rbp
    ret              # return
    
call_proc:
    sub   $16, %rsp
    movq  %edi,  8(%rsp)
    xorq  %edi,  %edi
    add   $0x8,  %edi
    movq  $0x10, %esi
    movq  %0x43(%rsp),   %rdx
    movq  $0x125 %rcx
    call proc
    movq  (%rsp), %edi
    addq  %edi,  %rax
    ret
    
# -------- stack result ---------
# |             |   orig %edi   | 8
# |          (unused)           | 0
# |        return address       | -
# |    orig rbp:     0x0        | callee - 8
# -------------------------------

Notes: the unused space is prepare for SIMD usage. On this stage, we can ignore it.

The caller saved register %rbp is pushed and set it as origin stack start position.

Local variable storage

There many example that variable are stored in registers, but at times that local variable should be load in memory. The common cases is:

  • There are not enough registers to hold all of the local data
  • The address operator ‘&’ is applied to local variable, and hense we must be able to generate an address for it
  • Some of the local variables are arrays or structures so that it should be accessed as array or structure references.

As for example code, please refer Figure 3.32

In convention, the former variable should be pushed in the higher address of stack and the later ones could be set in the lower ones. Such as:

|_____________________|
|___x2____|____x1_____| 16
|_________x3__________| 8
|_______________|__x4_| 0

Alignment

Many computer systems place restrictions on the allowable addresses for primitive data types, requiring that the address for some objects must be a multiple of some value K. Such restrictions simplify the design of hardware forming the interface between the processor and the memory system. Also, address of stack frame do the same thing, so as to be refered in a correct way. As an example of Practice Problem 3.49,

+------------------------+
+    return address      +  8
+------------------------+
+    saved %rbp          +  0
+------------------------+
+       (Unused)         + -8
+------------------------+
+                        + e1
+------------------------+
+                        +
+            P           + 8n bytes
+                        +
+------------------------+
+                        + e2
+------------------------+

Every part of the stack frame should be a multiple of 8, so that e1+P+e2 should be a multiple of 16, hense we could embed a slot of memory which address is a multiple of 8.

Variable-Size Stack Frames

The variable-size stack frames means that the size of stack frame could not be determined at compile time. Further more, the variable, maybe array of struct, should be referenced by its address. Therefore, we should use a technique of managing such condition.

As Figure 3.43 :

long vframe(long n, long idx, long *q) {
    long i;
    long *p[n];
      p[0] = &i;
      for (i = 1; i < n; i++)
      p[i] = q;
      return *p[idx];
}

Portions of generated assembly code:

vframe:
    pushq    %rbp        # Set old %rbp
    movq    %rsp, %rbp    # Set frame pointer
    subq    $16, %rsp    # Allocate space for array p
    leaq    22(, %rdi, 8), %rax    # Make it to be a multiple of 16
    andq    $-16, %rax
    subq    %rax, %rsp    # Allocate space for array p
    leaq    7(%rsp), %rax
    shrq    $3, %rax
    leaq    0(, %rax, 8), %r8
    movq    %r8, %rcx
    
    # .....
    
.L3:
    movq    %rdx, (%rcx, %rax, 8)    # Set p[i] to q
    addq    $1, %rax                 # Increment i
    movq    %rax, -8(%rbp)            # Store on the stack
.L2:
    movq    -8(%rbp), %rax            # Retrieve i
    cmpq    %rdi, %rax
    jl        .L3
    
#    .....
    leave
    ret
Note the way to refer the array is that, it refer it by pointer register %rbp

At last of the program, it restore the original pointer to the %rsp, then pop %rbp to restore the caller’s frame.

movq  %rbp, %rsp    # Set stack pointer to beginning of frame
popq  %rbp          # Restore

This instruction combination has the effect of deallocating the entire stack frame.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末枕荞,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子私爷,更是在濱河造成了極大的恐慌,老刑警劉巖蓬痒,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件埋涧,死亡現(xiàn)場(chǎng)離奇詭異限书,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)烹卒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)闷盔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人旅急,你說(shuō)我怎么就攤上這事逢勾。” “怎么了藐吮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵溺拱,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谣辞,道長(zhǎng)迫摔,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任泥从,我火速辦了婚禮句占,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘躯嫉。我一直安慰自己纱烘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布祈餐。 她就那樣靜靜地躺著擂啥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪昼弟。 梳的紋絲不亂的頭發(fā)上啤它,一...
    開(kāi)封第一講書(shū)人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音舱痘,去河邊找鬼。 笑死离赫,一個(gè)胖子當(dāng)著我的面吹牛芭逝,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播渊胸,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼旬盯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起胖翰,我...
    開(kāi)封第一講書(shū)人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤接剩,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后萨咳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體懊缺,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年培他,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鹃两。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舀凛,死狀恐怖俊扳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猛遍,我是刑警寧澤馋记,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站懊烤,受9級(jí)特大地震影響抗果,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜奸晴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一冤馏、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寄啼,春花似錦逮光、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至乙帮,卻和暖如春杜漠,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背察净。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工驾茴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氢卡。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓锈至,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親译秦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子峡捡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容