DevLog ๐Ÿ“จ

[DevLog][PintOS] PRJ3 Virtual Memory/Memory Management to Stack Growth

cece00 2023. 10. 17. 08:33

Project3: Virtual Memory

01) Memory management

struct page

์š”๊ตฌ ํŽ˜์ด์ง• (Demand Paging)์„ ๊ตฌํ˜„ํ•˜๊ณ , ์Šค์™‘ ์ธ/์•„์›ƒ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ํŽ˜์ด์ง€ ๊ตฌ์กฐ์ฒด๊ฐ€ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„ ์–ธ๋˜์–ด ์žˆ๋‹ค. va๋Š” ํŽ˜์ด์ง€์˜ ์‹œ์ž‘ ์ฃผ์†Œ, ์ฆ‰ ์œ ์ € ํ”„๋กœ์„ธ์Šค์˜ ๊ฐ€์ƒ์ฃผ์†Œ์ด๋‹ค. frame์€ ํŽ˜์ด์ง€์™€ ๋งคํ•‘๋œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ตฌ์กฐ์ฒด๋กœ, ๋งคํ•‘ ์ „๊นŒ์ง€๋Š” NULL๋กœ ์œ ์ง€๋œ๋‹ค.

struct page {
  const struct page_operations *operations;
  void *va;              /* Address in terms of user space */
  struct frame *frame;   /* Back reference for frame */

  union {
    struct uninit_page uninit;
    struct anon_page anon;
    struct file_page file;
#ifdef EFILESYS
    struct page_cache page_cache;
#endif
  };
};

ํ•€ํ† ์Šค์˜ PRJ3์—์„œ๋Š” ํŽ˜์ด์ง€๋ฅผ ์„ธ ๊ฐ€์ง€ ํƒ€์ž…์œผ๋กœ ๋‚˜๋ˆ„๋Š”๋ฐ, (page_cache๋ฅผ ์ œ์™ธํ•˜๊ณ  ๋ณด์ž๋ฉด) uninit, anon, file์ด๋‹ค. anon์€ ์Šคํƒ/ํž™๊ณผ ๊ฐ™์€ anonymous ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋งํ•œ๋‹ค. file์€ mmap์„ ํ†ตํ•ด ํŒŒ์ผ๊ณผ ๋งคํ•‘๋œ ๋ฉ”๋ชจ๋ฆฌ, ๋˜๋Š” ์ดˆ๊ธฐ์— lazy_load_segment ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์˜ฌ๋ฆฐ .text, .data ์„ธ๊ทธ๋จผํŠธ์™€ ๊ฐ™์€ file_backed_memory ๋ฅผ ๋งํ•œ๋‹ค. uninit์€ ๊ฐ€์ƒ์ฃผ์†Œ์˜ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์ด ์˜ˆ์•ฝ๋˜์–ด ์žˆ์ง€๋งŒ, ์‹ค์ œ๋กœ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋งคํ•‘๋˜์ง€ ์•Š์€ ์ƒํƒœ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ๋”ฐ๋ผ์„œ, page fault๊ฐ€ ๋ฐœ์ƒํ–ˆ๋Š”๋ฐ, ํ•ด๋‹น ์ฃผ์†Œ๊ฐ€ uninit type์˜ ํŽ˜์ด์ง€๋ผ๋Š” ๊ฒƒ์„ ์ปค๋„์ด ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด, (์ฆ‰, lazy load๊ฐ€ ํ•„์š”ํ•œ ์ƒํ™ฉ์ž„์„ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด) ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ํ•ด๋‹น ๊ฐ€์ƒ์ฃผ์†Œ๋ฅผ ๋งคํ•‘ํ•˜์—ฌ anon ๋˜๋Š” file type์˜ ๋ฉ”๋ชจ๋ฆฌ๋กœ ์ดˆ๊ธฐํ™”ํ•ด ์ค„ ์ˆ˜ ์žˆ๋‹ค.

page map level 4

/* The function table for page operations.
 * This is one way of implementing "interface" in C.
 * Put the table of "method" into the struct's member, and
 * call it whenever you needed. */
struct page_operations {
  bool (*swap_in)(struct page *, void *);
  bool (*swap_out)(struct page *);
  void (*destroy)(struct page *);
  enum vm_type type;
};


#define swap_in(page, v) (page)->operations->swap_in((page), v)
#define swap_out(page) (page)->operations->swap_out(page)
#define destroy(page) if ((page)->operations->destroy) (page)->operations->destroy(page)
  • operations: ๊ฐ ํŽ˜์ด์ง€์˜ ๋™์ž‘์„ ์ •์˜ํ•œ๋‹ค. ํฌ์ธํŠธ๋Š” ํŽ˜์ด์ง€์˜ ํƒ€์ž…์ด ๋ณ€ํ•  ๋•Œ๋งˆ๋‹ค swap_in, swap_out, destroy ํ•„๋“œ์— ํ•ด๋‹น ํƒ€์ž…์˜ ์—ฐ์‚ฐ์„ ๊ตฌํ˜„ํ•œ ํ•จ์ˆ˜๋ฅผ ๋งคํ•‘ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด, ํŽ˜์ด์ง€์˜ ํƒ€์ž…์— ๊ด€๊ณ„์—†์ด swap_in ๋งคํฌ๋กœ๋ฅผ ์‚ฌ์šฉํ•ด ๊ฐ ํŽ˜์ด์ง€๋ณ„๋กœ ๋‹ค๋ฅธ ๋ฃจํ‹ด์„ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. uninit type์˜ swap_in์„ ์‹คํ–‰ํ•˜๋ฉด, anon_initializer๊ฐ€ ์‹คํ–‰๋˜๊ณ , ์ด ๋•Œ operation ํ•„๋“œ๋ฅผ anon_operation์œผ๋กœ ๋ฐ”๊พธ์–ด ์ฃผ๋Š” ์‹์ด๋‹ค.
bool anon_initializer(struct page *page, enum vm_type type, void *kva) {
  /* Set up the handler */
  page->operations = &anon_ops;
  struct anon_page *anon_page = &page->anon;
  ...
  • union: ํŽ˜์ด์ง€์˜ ํƒ€์ž…์— ๋”ฐ๋ผ ๊ด€๋ฆฌํ•ด์•ผ ํ•  ์ •๋ณด๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผํ…Œ๋ฉด, uninit type์˜ ํŽ˜์ด์ง€๋Š”, ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋งคํ•‘๋  ๋•Œ ์‹คํ–‰ํ•ด์•ผ ํ•  ํ•จ์ˆ˜ (init, initializer ...) ํฌ์ธํ„ฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ฐ€ ๋งคํ•‘๋œ ์ดํ›„์— ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ์„œ lazy loadํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜ file_backed type์˜ ํŽ˜์ด์ง€๋Š”, ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋งคํ•‘์ด ํ•ด์ œ๋  ๋•Œ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์„ ํŒŒ์ผ์— ๋‹ค์‹œ ์จ ์ฃผ์–ด์•ผ ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋งคํ•‘ ์ •๋ณด๋ฅผ ๋“ค๊ณ  ์žˆ์–ด์•ผ ํ•œ๋‹ค. ์ด๋Ÿฌํ•œ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•ด์ฃผ๊ธฐ ์œ„ํ•ด ๊ตฌ์กฐ์ฒด ์•ˆ์— ํ•„๋“œ๋ฅผ ๊ฐ๊ฐ ๋‹ค ๋งŒ๋“ค ํ•„์š” ์—†์ด, (ํŽ˜์ด์ง€๋Š” ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ์ƒํƒœ๋งŒ ๊ฐ€์ง€๋ฏ€๋กœ) union์„ ์‚ฌ์šฉํ•œ๋‹ค. union์€ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์„ ๋ฉค๋ฒ„๊ฐ€ ๊ณต์œ ํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ธ๋ฐ, ๊ทธ ํฌ๊ธฐ๋Š” ๊ฐ€์žฅ ํฐ ๋ฉค๋ฒ„์˜ ํฌ๊ธฐ๋กœ ๊ฒฐ์ •๋œ๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ๋ฉค๋ฒ„ ๋ณ€์ˆ˜๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ž˜์„œ ์ƒํƒœ๋ณ„ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š”๋ฐ ์œ ์šฉํ•œ ๊ฒƒ ๊ฐ™๋‹ค.

struct

)

union

https://www.tcpschool.com/

Supplemetal Page Table

๋‹ค์–‘ํ•œ Page Fault ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด Supplemental Page Table์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ฅผํ…Œ๋ฉด, lazy loadํ•ด์•ผ ํ•˜๋Š” ๊ฐ€์ƒ์ฃผ์†Œ์ธ์ง€๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด SPT๋ฅผ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. ๋˜, SPT ์•ˆ์˜ page struct๋ฅผ ๋ณด๊ณ  ์ด ํŽ˜์ด์ง€๊ฐ€ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋งคํ•‘๋  ๋•Œ ์ˆ˜ํ–‰๋˜์–ด์•ผ ํ•  ์ž‘์—… (ex. file read)์„ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์šฐ๋ฆฌ ์กฐ๋Š” SPT๋ฅผ ํ•ด์‹œ ํ…Œ์ด๋ธ”๋กœ ๊ตฌํ˜„ํ–ˆ๋‹ค. ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ key์™€ value๋ฅผ ๋งคํ•‘ํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ์ด๋‹ค.

๐Ÿ‘€ Wikipedia ์ •๋ฆฌ
  • associative array (์—ฐ๊ด€ ๋ฐฐ์—ด): CS๋ถ„์•ผ์—์„œ associative array, map, symbol table, ๋˜๋Š” dictionary๋Š” ๊ฐ ํ‚ค๊ฐ€ ํ•ด๋‹น ์ง‘ํ•ฉ์—์„œ ์ตœ์†Œ ํ•œ ๋ฒˆ ์ด์ƒ ๋“ฑ์žฅํ•˜๋Š”, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ‚ค-๊ฐ’ ์Œ์˜ ์ง‘ํ•ฉ์œผ๋กœ ์ด๋ฃจ์–ด์ง„ ์ถ”์ƒ ์ž๋ฃŒํ˜•์ด๋‹ค. ์ˆ˜ํ•™์  ์šฉ์–ด์—์„œ associative array๋ž€ ์œ ํ•œํ•œ ์ •์˜์—ญ์„ ๊ฐ€์ง„ ํ•จ์ˆ˜์ด๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ lookup, remove, insert ์—ฐ์‚ฐ์„ ์ง€์›ํ•œ๋‹ค.
  • dictionary problem: associative array๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ํšจ์œจ์ ์ธ ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๊ณ ์ „์ ์ธ ๋ฌธ์ œ์ด๋‹ค. ์ด ๋ฌธ์ œ์˜ ํ•ด๋‹ต์œผ๋กœ ์ œ์‹œ๋œ ๊ฒƒ ์ค‘ ์ฃผ์š”ํ•œ ๋‘ ๊ฐ€์ง€๊ฐ€ ๋ฐ”๋กœ hash table๊ณผ search tree์ด๋‹ค.
  • hash table: ํ•ด์‹œ ํ…Œ์ด๋ธ”์€ ์—ฐ๊ด€ ๋ฐฐ์—ด์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด hash function์„ ์‚ฌ์šฉํ•ด ์ธ๋ฑ์Šค๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ , ๊ฐ’์„ ํ•ด๋‹น ์ธ๋ฑ์Šค์˜ ๋ฒ„ํ‚ท(๋˜๋Š” ์Šฌ๋กฏ)์— ์ €์žฅํ•œ๋‹ค. ์ €์žฅ๋œ ๊ฐ’์„ ์ฐพ๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋‹ค์‹œ hash function์„ ์‚ฌ์šฉํ•ด์„œ ์ธ๋ฑ์Šค์— ์ ‘๊ทผํ•œ๋‹ค. ์ด์ƒ์ ์œผ๋กœ๋Š”, ํ•˜๋‚˜์˜ ํ‚ค๊ฐ€ ํ•˜๋‚˜์˜ ๊ฐ’์œผ๋กœ ๋งคํ•‘๋˜์–ด์•ผ ํ•˜๊ธฐ์— ๊ฐ ๋ฒ„ํ‚ท์— ์ €์žฅ๋˜๋Š” ๊ฐ’์€ ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด์„œ, ๋ชจ๋“  ํ‚ค์— ๋Œ€ํ•ด ํ•ด์‹œ ํ•จ์ˆ˜์˜ ๋ฆฌํ„ด๊ฐ’์ด ์œ ๋‹ˆํฌํ•ด์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ํ•ด์‹œ ํ…Œ์ด๋ธ” ๋””์ž์ธ์€ ์™„๋ฒฝํ•˜์ง€ ์•Š์€ ํ•ด์‹œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์—, ๋‘˜ ์ด์ƒ์˜ ํ‚ค์— ๋Œ€ํ•ด ๊ฐ™์€ index๋ฅผ ์ƒ์„ฑํ•˜๋Š” hash collision์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

hash

pintos์˜ include/lib/kernel/hash.c์—์„œ ์ œ๊ณตํ•˜๋Š” ํ•ด์‹œ ํ…Œ์ด๋ธ” ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์ตœ์ดˆ 4๊ฐœ์˜ ๋ฒ„ํ‚ท์œผ๋กœ ํ•ด์‹œ ํ…Œ์ด๋ธ”์ด ์ดˆ๊ธฐํ™”๋˜๊ณ , ์ด ๋ฒ„ํ‚ท๋“ค์€ struct listํƒ€์ž…์„ ๊ฐ–๋Š”๋‹ค. ์ฆ‰, ๋ฒ„ํ‚ท ํ•˜๋‚˜์— ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ฐ’์ด ์ €์žฅ๋  ์ˆ˜ ์žˆ๊ณ , list์˜ ์‚ฌ์šฉ๋ฒ•๊ณผ ๋™์ผํ•˜๊ฒŒ ์ €์žฅํ•˜๊ณ ์ž ํ•˜๋Š” ๊ตฌ์กฐ์ฒด ์•ˆ์— hash_elemํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•จ์œผ๋กœ์„œ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ…Œ์ด๋ธ”์— ํ•˜๋‚˜๊ฐ€ insert๋  ๋•Œ ๋งˆ๋‹ค ํ•„์š”ํ•œ ๋ฒ„ํ‚ท์˜ ์ˆ˜๋ฅผ ์žฌ๊ณ„์‚ฐํ•˜์—ฌ (๊ฐ ๋ฒ„ํ‚ท ๋‹น BEST_ELEMS_PER_BUCKET๊ฐœ๋งŒ ์ €์žฅํ•˜๋„๋ก) ์žฌ๋ฐฐ์น˜ํ•˜๋Š” rehash ํ•จ์ˆ˜๋ฅผ ๋Œ๋ฆฐ๋‹ค. ๋ฒ„ํ‚ท์ด ๋Š˜์–ด๋‚  ํ•„์š”๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ rehashํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ lookup, insert, remove๋Š” $O(1)$ ์‹œ๊ฐ„๋ณต์žก๋„๋ฅผ ๊ฐ–๊ฒŒ ๋œ๋‹ค.

/* Returns the bucket in H that E belongs in. */
static struct list *find_bucket(struct hash *h, struct hash_elem *e) {
  size_t bucket_idx = h->hash(e, h->aux) & (h->bucket_cnt - 1);
  return &h->buckets[bucket_idx];
}
๐Ÿ‘€ ๋ฒ„ํ‚ท์˜ ๊ฐœ์ˆ˜๋Š” ์™œ 2์˜ ์ œ๊ณฑ์ˆ˜์ผ๊นŒ?

๋ฒ„ํ‚ท์€ 2์˜ ์ œ๊ณฑ์ˆ˜๋กœ ๋Š˜์–ด๋‚˜๋Š”๋ฐ, (4, 8, 16 , ...) ์ด๋Š” ํ•ด์‹œ ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๊ฐ€ ์ €์žฅ๋  ๋ฒ„ํ‚ท์˜ ์ธ๋ฑ์Šค๋ฅผ ๊ฒฐ์ •ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ชจ๋“ˆ๋Ÿฌ ์—ฐ์‚ฐ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ชฉ์ ์œผ๋กœ ์ดํ•ด๋  ์ˆ˜ ์žˆ๋‹ค. ๋ฒ„ํ‚ท์„ ์ฐพ๋Š” ์œ„ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด hash_code % bucket_count๊ฐ€ ์•„๋‹ˆ๋ผ hash_code & (bucket_count - 1)์ด๋Ÿฐ ์‹์œผ๋กœ ๋ชจ๋“ˆ๋Ÿฌ ์—ฐ์‚ฐ์„ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๋งŒ์•ฝ ๋ฒ„ํ‚ท์˜ ์ˆ˜๊ฐ€ 2์˜ ์ œ๊ณฑ์ˆ˜๋ผ๋ฉด bucket_count - 1์„ ํ•จ์œผ๋กœ์„œ ์ตœ์ƒ์œ„ 1๋น„ํŠธ ์ดํ•˜ ๋น„ํŠธ๋ฅผ ๋ฐ˜์ „์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค. ์ด ๊ฐ’์„ AND ์—ฐ์‚ฐ์„ ์ทจํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ชจ๋“ˆ๋Ÿฌ ์—ฐ์‚ฐ๊ณผ ๋™์ผํ•ด์ง€๊ฒŒ ๋œ๋‹ค. ๋น„ํŠธ ์—ฐ์‚ฐ์€ ๋ชจ๋“ˆ๋Ÿฌ ์—ฐ์‚ฐ ๋Œ€๋น„ ๋น ๋ฅด๋‹ค. (์ด๊ฑฐ ๋ง๊ณ  ๋˜ ๋‹ค๋ฅธ ์ด์œ ๊ฐ€ ์žˆ์„ ๊ฒƒ ๊ฐ™๋‹ค. ์ฐพ์•„๋ณผ๊ฒƒ..)

hash_code = 13 // 1101
buck_cnt  = 4  // 100

hash_code & (buck_cnt - 1) = 1101 & 0011 // 1 is result of modulo(hash_code, buck_cnt)

์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๊ฒฐ์ •ํ–ˆ์œผ๋‹ˆ spt์™€ ๊ด€๋ จ๋œ ํ•จ์ˆ˜๋ฅผ ๊ตฌํ˜„ํ•ด์ฃผ๋ฉด ๋œ๋‹ค. ๊ธฐ์กด ํ•ด์‹œ ์ฝ”๋“œ์— ์žˆ๋Š” ํ•จ์ˆ˜๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

  • supplemental_page_table_init: hash_init์„ ์ฝœํ•˜๊ณ , hash_hash_func์™€ (hash_find์— ํ•„์š”ํ•œ) hash_less_func์„ ๋„ฃ์–ด์ค€๋‹ค.
  • spt_find_page: ๊ฐ€์ƒ์ฃผ์†Œ๊ฐ’์„ ๊ธฐ์ค€์œผ๋กœ spt๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • spt_insert_page: ํŽ˜์ด์ง€๋ฅผ ํ•ด์‹œ ํ…Œ์ด๋ธ”์— ์‚ฝ์ž…ํ•œ๋‹ค.

struct frame

/* The representation of "frame" */
struct frame {
  void *kva; /* kernel virtual address */
  struct page *page;
};

๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๊ตฌ์กฐ์ฒด์ด๋‹ค. palloc_get_page๋กœ ๋ฐ›์•„์˜จ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์˜ kva, kernel virtual address๋ฅผ ์ €์žฅํ•œ๋‹ค. ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•ด ์Šค์™‘ ๋””์Šคํฌ ๊ณต๊ฐ„์œผ๋กœ evictํ•  ๊ฒฝ์šฐ์™€ ๊ฐ™์ด ํ”„๋ ˆ์ž„์„ ๊ด€๋ฆฌํ•  ๋•Œ ํ”„๋ ˆ์ž„ ํ…Œ์ด๋ธ”๊ณผ ํ”„๋ ˆ์ž„ ๊ตฌ์กฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒ ๋‹ค.

๐Ÿ‘€ ์ปค๋„ ๊ฐ€์ƒ ์ฃผ์†Œ?

pintos ์ฝ”๋“œ๋ฅผ ์งœ๋‹ค ๋ณด๋ฉด ๋‘ ๊ฐ€์ง€ ์ฃผ์†Œ์ฒด๊ณ„๋ฅผ ๋งˆ์ฃผํ•˜๊ฒŒ ๋œ๋‹ค. ํ•˜๋‚˜๋Š” pml4๋ฅผ ์‚ฌ์šฉํ•œ ์ฃผ์†Œ์ฒด๊ณ„๋กœ, ๊ฐ ๋ ˆ๋ฒจ์˜ ํŽ˜์ด์ง€ ํ…Œ์ด๋ธ”์˜ ์˜คํ”„์…‹์„ 9๋น„ํŠธ์”ฉ, ๊ทธ๋ฆฌ๊ณ  ํ”„๋ ˆ์ž„ ์˜คํ”„์…‹์„ 12๋น„ํŠธ ์ €์žฅํ•˜๊ณ  ์žˆ๋Š” ๊ฐ€์ƒ์ฃผ์†Œ๋‹ค. ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ์ปค๋„์˜ ์ฃผ์†Œ๊ณต๊ฐ„์„ ํŠน์ •ํ•˜๊ธฐ ์œ„ํ•ด ์„ค์ •๋œ ๋ผ์ธ์ธ KERN_BASE๋ฅผ ๋”ํ•˜๊ฑฐ๋‚˜ ๋บŒ์œผ๋กœ์„œ ๊ฐ€์ƒ์ฃผ์†Œ์™€ ๋ฌผ๋ฆฌ์ฃผ์†Œ๋ฅผ ๋งคํ•‘ํ•˜๋Š” ์ฃผ์†Œ์ฒด๊ณ„๋กœ, ์ปค๋„ ์ฝ”๋“œ์—์„œ ์ž‘๋™ํ•œ๋‹ค. ..? ์ด ๋ถ€๋ถ„์„ ์ข€ ๋” ์•Œ๊ธฐ ์œ„ํ•ด์„œ๋Š” palloc.c์˜ palloc_init์„ ๋ณด์•„์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค..

๐Ÿ‘€ loader.S์˜ pml4 ๋งŒ๋“œ๋Š” ๋ถ€๋ถ„
/* loader.h */ 
/* Physical address of kernel base. */
#define LOADER_KERN_BASE 0x8004000000

/* start.S */
#define RELOC(x) (x - LOADER_KERN_BASE)

...

#### Create page directory and page table and
#### set page directory base register (cr3).
setup_page_table:
# 1. fill boot_pml4e with zeros
    lea (RELOC(boot_pml4e)), %edi  // boot_pml4e์—์„œ LOADER_KERN_BASE๋ฅผ ๋นผ์„œ %edi ๋ ˆ์ง€์Šคํ„ฐ์— ์ €์žฅ
    xor %eax, %eax               // %eax๋ฅผ 0์œผ๋กœ ์ดˆ๊ธฐํ™”
    mov $0x400, %ecx             // %ecx = $0x400 (1024)
    rep stosl (%edi)             // %eax๋ฅผ %edi๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์œ„์น˜์— ์ €์žฅํ•˜๊ณ  %edi๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค๋Š” ๊ฒƒ์„ %ecx๋งŒํผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

# 2. set pdpts
    lea (RELOC(boot_pml4e)), %edi  // pml4 physical addr
    lea (RELOC(boot_pdpt1)), %ebx  // pdpt1 physical addr
    orl $(PTE_P | PTE_W), %ebx     // pdpt1 is p & w
    mov %ebx, (%edi)               // pml4 save pdpt1
    lea (RELOC(boot_pdpt2)), %ebx  // pdpt2 physical addr
    orl $(PTE_P | PTE_W), %ebx     // pdpt2 is p & w
    mov %ebx, 8(%edi)              // pml4 save pdpt2

# 3. set pdpes
    lea (RELOC(boot_pdpt1)), %edi  // pdpt1 physical addr
    lea (RELOC(boot_pde1)), %ebx   // pde1 physical addr
    orl $(PTE_P | PTE_W), %ebx     // pde1 is p & w
    mov %ebx, (%edi)               // pdpt1 save pde1

    lea (RELOC(boot_pdpt2)), %edi  // pdpt2 physical addr
    lea (RELOC(boot_pde2)), %ebx   // pde2 physical addr
    orl $(PTE_P | PTE_W), %ebx     // pde2 is p & w
    mov %ebx, (%edi)               // pdpt2 save pde2

# 4. setup pdes
    mov $128, %ecx
    lea (RELOC(boot_pde1)), %ebx   // pde1 physical addr
    lea (RELOC(boot_pde2)), %edx   // pde2 physical addr
    add $256, %edx                 // %edx = 256 (2^8)
    mov $(PTE_P | PTE_W | 0x180), %eax // 0x183

fill_pdes:
    mov %eax, (%ebx)               // pde1 = %eax
    mov %eax, (%edx)               // pde2 = %eax
    add $8, %ebx                   // next
    add $8, %edx                   // next
    add $0x200000, %eax            // %eax += 2MB
    dec %ecx                       // %ecx --
    cmp $0, %ecx                   // %ecx = 128, loops 128
    jne fill_pdes

# 5. Load page directory base register (cr3).
    lea (RELOC(boot_pml4e)), %eax
    mov %eax, %cr3

...

// reserve 0x1000 (4096) bytes memory.
boot_pml4e:
  .space  0x1000
boot_pdpt1:
  .space  0x1000
boot_pdpt2:
  .space  0x1000
boot_pde1:
  .space  0x1000
boot_pde2:
  .space  0x1000
๐Ÿ‘€ ์•Œ์•„๋ณผ ๋‚ด์šฉ๋“ค..
  • RELOC ๋งคํฌ๋กœ๋ฅผ ํ†ตํ•ด kernel virtual address์—์„œ physical address๋กœ ๋ฐ”๊พธ์–ด์„œ pte์— ๊ธฐ๋กํ•˜๊ณ  ์žˆ๋Š”๋ฐ, ๊ทธ๋ ‡๋‹ค๋ฉด kernel va์™€ pa์˜ ๋งคํ•‘์ด ์–ธ์  ๊ฐ€ ์ฝ”๋“œ์ƒ์—์„œ ์ด๋ฃจ์–ด์ง„ ์ƒํƒœ์ผ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ ์ž‘์—…์„ ํ•˜๋Š” ๋ถ€๋ถ„์€ ์–ด๋””์— ์žˆ๋Š”์ง€?
  • page_init์—์„œ ๋งŒ๋“œ๋Š” base_pml4๋ž‘์€ ๋ญ๊ฐ€ ๋‹ค๋ฅธ์ง€? โ†’ base_pml4๋Š” ๋ชจ๋“  ์œ ์ € ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ผ์ฐจ์ ์œผ๋กœ ์ƒ์†ํ•˜๋Š”(?) ๋‚ด์šฉ์ด๋‹ค. base_pml4์—๋Š” ์ปค๋„ ์ฝ”๋“œ๊ฐ€ write-protectํ•˜๊ฒŒ ์ฃผ์†Œ ์ง€์ •์ด ๋˜์–ด ์žˆ๋Š”๋ฐ, pml4_create์—์„œ ๋ฐ”๋กœ ์ด pml4์˜ ๋‚ด์šฉ์„ ๊ฐ€์ ธ์˜จ๋‹ค. pml4_activate(NULL); ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ pml4 ? pml4 : base_pml4 ์‹์œผ๋กœ base_pml4๊ฐ€ cr3 ๋ ˆ์ง€์Šคํ„ฐ์— ์˜ฌ๋ผ๊ฐ„๋‹ค.
/* Creates a new page map level 4 (pml4) has mappings for kernel
 * virtual addresses, but none for user virtual addresses.
 * Returns the new page directory, or a null pointer if memory
 * allocation fails. */
uint64_t *pml4_create(void) {
    uint64_t *pml4 = palloc_get_page(0);
    if (pml4) memcpy(pml4, base_pml4, PGSIZE);
    return pml4;
}

02) Anonymous Page

๋””์Šคํฌ ๊ธฐ๋ฐ˜์ด ์•„๋‹Œ ํŽ˜์ด์ง€, ์ฆ‰ ์ต๋ช… ํŽ˜์ด์ง€๋Š” ์ฃผ๋กœ ์Šคํƒ ๋˜๋Š” ํž™ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

  • Anonymous page: ํŒŒ์ผ๊ณผ ๋งคํ•‘๋˜์ง€ ์•Š์€ ํŽ˜์ด์ง€
  • File-backed page: ๋””์Šคํฌ์— ์žˆ๋Š” ํŒŒ์ผ๊ณผ ์ง์ ‘ ๋งคํ•‘๋œ ํŽ˜์ด์ง€๋กœ, ์ด ํŽ˜์ด์ง€์—์„œ ๋ณ€๊ฒฝ๋œ ๋‚ด์šฉ์€ ํŒŒ์ผ์—๋„ ๋ฐ˜์˜๋˜์–ด์•ผ ํ•จ.
๐Ÿ‘€ ELF ํŒŒ์ผ์„ ๋กœ๋“œํ•  ๋•Œ file-backed๊ฐ€ ์•„๋‹Œ anonymous๋กœ ์ง€์ •ํ•˜๋Š” ์ด์œ ?
static bool load_segment(struct file *file, off_t ofs, uint8_t *upage,
                         uint32_t read_bytes, uint32_t zero_bytes,
                         bool writable) {
  ...
  while (read_bytes > 0 || zero_bytes > 0) {
    ...
    if (!vm_alloc_page_with_initializer(VM_ANON, upage, writable,
                                        lazy_load_segment, aux)) {
      return false;
    }

File-backed page๋Š” ํŽ˜์ด์ง€์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋””์Šคํฌ์˜ ํŒŒ์ผ์— ์ €์žฅํ•ด์•ผ ํ•˜๋Š” ํŽ˜์ด์ง€ ์ข…๋ฅ˜๋ฅผ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•œ ํƒ€์ž…์ด๋‹ค. ELF ํŒŒ์ผ์˜ ์ฝ”๋“œ์™€ ๋ฐ์ดํ„ฐ(.data, .bss) ์˜์—ญ์€ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค๊ณ  ํ•ด์„œ ๋””์Šคํฌ์— ๋ฐ˜์˜๋˜๋ฉด ์•ˆ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ VM_ANON์œผ๋กœ initialize ํ•˜๋„๋ก ํƒ€์ž…์„ ์ง€์ •ํ•œ๋‹ค. (๊ทธ๋ฆฌ๊ณ  swap out๋˜์—ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ swap in ๋˜์—ˆ์„ ๋•Œ๋„ ์ด์ „์˜ ๋ณ€๊ฒฝ๋‚ด์šฉ์„ ์œ ์ง€ํ•ด์•ผ ํ•œ๋‹ค. ์ฆ‰, ํŒŒ์ผ์ด ์•„๋‹Œ swap disk์— ๊ธฐ๋ก๋˜์–ด์•ผ ํ•œ๋‹ค.)

Lazy loading segments

ELF ์‹คํ–‰ ํŒŒ์ผ์„ lazyํ•˜๊ฒŒ loadํ•ด๋ณด์ž

bool vm_alloc_page_with_initializer(enum vm_type type, void *upage,
                                    bool writable, vm_initializer *init,
                                    void *aux);

VM์˜ load_segmentํ•จ์ˆ˜๋Š” void* kpage = palloc_get_page(PAL_USER | PAL_ZERO); ๋Œ€์‹  ์ด ํ•จ์ˆ˜๋ฅผ ๋ถˆ๋Ÿฌ์„œ ๊ฐ€์ƒ์ฃผ์†Œ๊ณต๊ฐ„์„ ์˜ˆ์•ฝํ•ด๋‘๊ณ , ์‹ค์ œ ํ•ด๋‹น ์ฃผ์†Œ์—์„œ ํŽ˜์ด์ง€ ํดํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋งคํ•‘ํ•ด์ค€๋‹ค. ์˜ˆ์•ฝ๋œ ๊ฐ€์ƒ์ฃผ์†Œ๊ณต๊ฐ„์ž„์„ ์•Œ๊ธฐ ์œ„ํ•ด spt๋ฅผ ํ™œ์šฉํ•œ๋‹ค. ์ฆ‰, ์œ„ ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•˜๋ฉด, 4KB ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋ฐ›๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, struct page ๋ผ๋Š” ์ž‘์€ ๊ตฌ์กฐ์ฒด๋งŒ ๋งŒ๋“ค์–ด์„œ ํ˜„์žฌ ์Šค๋ ˆ๋“œ(๋˜๋Š” ์œ ์ € ํ”„๋กœ์„ธ์Šค)์˜ spt์— ๋„ฃ์–ด ๋‘”๋‹ค.

struct page* page = calloc(1, sizeof(struct page));
switch(type)
    case VM_ANON:
        uninit_new(page, upage, init, type, aux, anon_initializer);
    case VM_FILE:
        uninit_new(page, upage, init, type, aux, file_backed_initializer);
    ...

spt_insert_page(&thread_current()->spt, page);

uninit.c์— ์žˆ๋Š” uninit_newํ•จ์ˆ˜๋Š” ์ฃผ์–ด์ง„ ์ธ์ž๋ฅผ page ๊ตฌ์กฐ์ฒด์˜ ํ•„๋“œ์— ๋„ฃ์–ด์ฃผ๋Š” ํ•จ์ˆ˜์ด๋‹ค. ์•„์ง ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์€, ์ฆ‰ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ์™€ ๋งคํ•‘๋˜์ง€ ์•Š์€ ํŽ˜์ด์ง€๋ฅผ ์˜๋ฏธํ•œ๋‹ค. ์ธ์ž๋กœ ์ „๋‹ฌ๋œ type์— ๋”ฐ๋ผ initializer ํ•จ์ˆ˜๋ฅผ ๋„ฃ์–ด ์ฃผ๋ฉด page->uninit->initializer ํ•„๋“œ์— ๋„ฃ์–ด๋‘์—ˆ๋‹ค๊ฐ€ ์‹คํ–‰๋œ๋‹ค. (์–ธ์ œ ์‹คํ–‰๋˜๋ƒ๋ฉด!! uninit์˜ swap_in ๋•Œ)

load_segment ํ•จ์ˆ˜๋Š” ์œ„์™€ ๊ฐ™์ด ๊ฐ€์ƒ์ฃผ์†Œ๊ณต๊ฐ„์„ ์˜ˆ์•ฝํ•ด๋‘๋Š” ๊ฒƒ์œผ๋กœ ์ข…๋ฃŒ๋œ๋‹ค. ๊ทธ ํ›„ ํ”„๋กœ์„ธ์Šค๊ฐ€ ์‹คํ–‰๋˜์–ด ํ•ด๋‹น ํŽ˜์ด์ง€์— fault๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์‹ค์ œ ELF ํŒŒ์ผ์˜ ๋‚ด์šฉ์„ ์ฝ์–ด์„œ ๋กœ๋“œํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

// init.c ๊ณผ์ • ์ค‘ ํŽ˜์ด์ง€ ํดํŠธ์˜ vec_no์— page_fault ํ•จ์ˆ˜๋ฅผ ๋งคํ•‘ํ•ด ๋‘”๋‹ค.
// ํƒ€์ด๋จธ ์ธํ„ฐ๋ŸฝํŠธ๋Š” intr_register_ext๋กœ ์ดˆ๊ธฐํ™”ํ–ˆ์ง€๋งŒ
// page fault๋Š” internal exception์ด๋ฏ€๋กœ intr_register_int๋กœ ์ดˆ๊ธฐํ™”.
void exception_init(void) {
  ...
  intr_register_int(14, 0, INTR_OFF, page_fault, "#PF Page-Fault Exception");
}

// intr_handler ํ•จ์ˆ˜ ์•ˆ์—์„œ page_fault๊ฐ€ ์ฝœ ๋œ๋‹ค.
static void page_fault(struct intr_frame *f) {
  bool not_present;    /* True: not-present page, false: writing r/o page. */
  bool write;          /* True: access was write, false: access was read. */
  bool user;           /* True: access by user, false: access by kernel. */
  void *fault_addr;    /* Fault address. */
  struct thread *curr; /* Current thread. */

  fault_addr = (void *)rcr2();

  /* Turn interrupts back on (they were only off so that we could
     be assured of reading CR2 before it changed). */
  intr_enable();

  /* Determine cause. */
  not_present = (f->error_code & PF_P) == 0;
  write = (f->error_code & PF_W) != 0;
  user = (f->error_code & PF_U) != 0;

#ifdef VM
  /* For project 3 and later. */
  if (vm_try_handle_fault(f, fault_addr, user, write, not_present)) return;
#endif

exception.c์˜ exception_init ์—์„œ ํŽ˜์ด์ง€ ํดํŠธ์˜ vec_no์ธ 14๋ฒˆ๊ณผ page_fault ํ•จ์ˆ˜๊ฐ€ ๋งคํ•‘๋˜๊ณ , 14๋ฒˆ ์ธํ„ฐ๋ŸฝํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ด ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋œ๋‹ค. ๊ทธ ์•ˆ์˜ vm_try_handle_fault๊ฐ€ ์šฐ๋ฆฌ๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ํ•จ์ˆ˜์ด๋‹ค.

์š”๊ตฌ ํŽ˜์ด์ง•์„ ๊ตฌํ˜„ํ•˜๋ฏ€๋กœ, ํŽ˜์ด์ง€ ํดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค ์ค‘ ๋‹จ์ˆœ bad ptr์ด ์•„๋‹Œ lazy loading ์ธ ๊ฒฝ์šฐ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

+) bad pointer๊ฐ€ ์•„๋‹Œ ์„ธ ๊ฐ€์ง€ fault case

  1. lazy loading: ํŽ˜์ด์ง€์— ํ•ด๋‹น ํŒŒ์ผ๋กœ๋ถ€ํ„ฐ ์ฝ์–ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋“œํ•ด์ค˜์•ผ ํ•œ๋‹ค. ๋˜๋Š” ์ต๋ช… ํŽ˜์ด์ง€์ธ ๊ฒฝ์šฐ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•ด ๋งคํ•‘ํ•ด์•ผ ํ•œ๋‹ค.
  2. write-protect: ์“ฐ๊ธฐ ๋ณดํ˜ธ๋œ ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์“ฐ๊ธฐ ์ ‘๊ทผ์ธ ๊ฒฝ์šฐ ์‹ค์ œ๋กœ fault๊ฐ€ ๋ฐœ์ƒํ•ด์•ผ ํ•œ๋‹ค.
  3. swap-out page: ํŽ˜์ด์ง€ ๊ต์ฒด๋กœ ์ธํ•ด ํŽ˜์ด์ง€๊ฐ€ ์Šค์™‘ ๋””์Šคํฌ๋กœ out๋œ ์ƒํ™ฉ์ด๋ผ๋ฉด, ๋‹ค์‹œ inํ•ด์•ผ ํ•œ๋‹ค.

lazy loading๋งŒ ์ƒ๊ฐํ•ด ๋ณด๋ฉด, ๋งŒ์•ฝ fault๊ฐ€ ๋ฐœ์ƒํ•œ address๊ฐ€ ์ด์ „์— ์˜ˆ์•ฝ๋œ ์ฃผ์†Œ๊ณต๊ฐ„์ด๋ผ๋ฉด, spt์—์„œ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ spt๋ฅผ ๊ฒ€์ƒ‰ํ•ด์„œ ํ•ด๋‹น ๊ฐ€์ƒ์ฃผ์†Œ๋ฅผ ๊ฐ–๋Š” ํŽ˜์ด์ง€ ์ •๋ณด๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์žˆ๋‹ค๋ฉด ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋งคํ•‘ํ•ด์ค€๋‹ค. ์—†๋‹ค๋ฉด return false ํ•œ๋‹ค.

bool vm_do_claim_page(struct page* page) {
    struct frame* frame = vm_get_frame();

    frame->page = page;
    page->frame = frame;

    /* mark page as present. */
    page->flags = page->flags | PTE_P;

    return swap_in(page, frame->kva);
}

๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•˜๊ณ , ๊ตฌ์กฐ์ฒด๋ผ๋ฆฌ ์—ฐ๊ฒฐํ•œ ํ›„ swap_in์„ ์‹คํ–‰ํ•œ๋‹ค. ์ด ๋•Œ๋Š” uninit_operation์˜ swap_in์ด ์‹คํ–‰๋˜๋Š”๋ฐ, ์ด๋Š” uninit_initialize ํ•จ์ˆ˜์ด๋‹ค.

/* Initalize the page on first fault */
static bool uninit_initialize(struct page *page, void *kva) {
  struct thread* curr = thread_current();
  struct uninit_page *uninit = &page->uninit;

  /* Fetch first, page_initialize may overwrite the values */
  vm_initializer *init = uninit->init;
  void *aux = uninit->aux;

  return uninit->page_initializer(page, uninit->type, kva) &&
         (init ? init(page, aux) : true) && install_page(page);
}

์—ฌ๊ธฐ์„œ ์ด์ „์— vm_alloc_page_with_initializer์—์„œ ์ธ์ž๋กœ ๋„˜๊ฒผ๋˜ init, aux์™€ initializer ๊ฐ€ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. anon_initializer ๋˜๋Š” file_backed_initializer๋ฅผ ์‹คํ–‰ํ•˜๊ณ , install_page๋กœ ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ pml4์— ๋งคํ•‘์„ ๋งŒ๋“ค์–ด ์ฃผ์—ˆ๋‹ค. ์ด ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•จ์œผ๋กœ์„œ lazy loading ๊ณผ์ •์ด ๋งˆ๋ฌด๋ฆฌ๋œ๋‹ค.

๋‘ ๋ฒˆ์งธ ๊ทธ๋ฆผ์— ํ•˜๋‚˜ ๋น ์ง„ ๊ฒŒ ์žˆ๋Š”๋ฐ, ๋งˆ์ง€๋ง‰์œผ๋กœ ํ•ด๋‹น ๊ฐ€์ƒ์ฃผ์†Œ์™€ ํ• ๋‹น๋œ ๋ฉ”๋ชจ๋ฆฌ์˜ ๋ฌผ๋ฆฌ์ฃผ์†Œ๋ฅผ ํ˜„์žฌ ์Šค๋ ˆ๋“œ์˜ pml4์— setํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Copy spt table

fork ์‹œ์Šคํ…œ ์ฝœ์„ ํ˜ธ์ถœํ•  ๋•Œ, ๋ถ€๋ชจ์™€ ์ž์‹ ๊ฐ„์˜ spt table์„ ๋ณต์ œํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์ฃผ์˜ํ•  ์ ์€, file_info์™€ ๊ฐ™์ด malloc์œผ๋กœ ํ• ๋‹น๋ฐ›์€ ๊ตฌ์กฐ์ฒด ์ •๋ณด๋„ ๋ณต์ œํ•ด์•ผ ํ•œ๋‹ค๋Š” ์ ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํƒ€์ž…๋ณ„๋กœ ๋ณต์ œ๋ฅผ ์ž˜ ํ•ด์ฃผ๋Š” ๊ฒŒ ์ค‘์š”ํ•˜๋‹ค.

๋˜ ํ”„๋กœ์„ธ์Šค fork๋ฅผ ํ•  ๋•Œ, lazyํ•˜๊ฒŒ loadํ•  ํŒŒ์ผ์ด ๋ถ€๋ชจ ํ˜น์€ ์ž์‹์—์„œ ๋จผ์ € ๋‹ซํ˜€ ๋ฒ„๋ฆฌ๋Š” ๊ฒฝ์šฐ๋ฅผ ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ๋™์ผํ•œ ํŒŒ์ผ์„ file_duplicate๊ณผ ๊ฐ™์€ ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ํ•œ๋ฒˆ ๋” ์—ด์–ด ์ฃผ๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•˜๋‹ค. (ํŠนํžˆ ELF ์‹คํ–‰ ํŒŒ์ผ์˜ ๊ฒฝ์šฐ)

static void spt_copy_page(struct hash_elem *e, void *aux) {
  struct supplemental_page_table *dsc_spt =
      (struct supplemental_page_table *)aux;
  struct hash *dsc_hash = &dsc_spt->hash;
  struct page *src_page = hash_entry(e, struct page, elem);

  /* Copy spt entries. */
  struct page *dsc_page = calloc(1, sizeof(struct page));
  memcpy(dsc_page, src_page, sizeof(struct page));

  /* Deconnect from parent's hash table. */
  memset(&dsc_page->elem, 0, sizeof(struct hash_elem));
  hash_insert(dsc_hash, &dsc_page->elem);

  if (!pg_present(src_page)) {
    /* If uninitialized segement page, copy file info. */
    struct file_info *dsc_aux;
    struct file_info *src_aux = (struct file_info *)src_page->uninit.aux;

    dsc_aux = calloc(1, sizeof(struct file_info));
    memcpy(dsc_aux, src_aux, sizeof(struct file_info));
    dsc_page->uninit.aux = dsc_aux;

  } else {
    /* Claim page if present. */
    struct frame *dsc_frame = vm_get_frame();
    ASSERT(src_page->frame->kva)
    ASSERT(dsc_page->frame->kva)

    dsc_page->frame = dsc_frame;
    dsc_frame->page = dsc_page;
    memcpy(dsc_page->frame->kva, src_page->frame->kva, PGSIZE);

    install_page(dsc_page);
  }
}

03) Stack Growth

์Šคํƒ์˜ ํฌ๊ธฐ๋Š” ์ดˆ๊ธฐ์— 4KB๋กœ ์„ธํŒ…๋œ๋‹ค. ์Šคํƒ์€ setup_stack ํ•จ์ˆ˜๊ฐ€ ๋ฆฌํ„ด๋˜๊ธฐ ์ „์— ์‹ค์ œ ๋ฌผ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น๋ฐ›๋„๋ก ๊ตฌํ˜„ํ•˜๋Š”๋ฐ, ์ด๋Š” ์‹คํ–‰ํŒŒ์ผ load๊ณผ์ •์—์„œ setup_stack์ด ํ˜ธ์ถœ๋œ ์งํ›„ ์‹คํ–‰ํŒŒ์ผ์˜ ์ธ์ž๋ฅผ ์Šคํƒ์— ์Œ“์•„์ฃผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋งŒ์•ฝ ์ฆ‰์‹œ 1๊ฐœ ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹น๋ฐ›์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ธ์ž๋ฅผ ์Œ“๋Š” ๊ณผ์ •์—์„œ ํดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ , ๊ทธ ๋•Œ ์Šคํƒ์ด ๋งŒ๋“ค์–ด์งˆ์ˆ˜๋„ ์žˆ(๊ธด ์žˆ)๋‹ค. ํ•˜์ง€๋งŒ lazy loading์ด ์‹ค์ œ๋กœ ์ ‘๊ทผ์ด ์–ธ์ œ ์ด๋ฃจ์–ด์งˆ ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์ ‘๊ทผ ํ›„์— ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹นํ•ด์ฃผ๋Š” ์ „๋žต ์ด๋ผ๋Š” ์ ์—์„œ, ์ ‘๊ทผ์ด ์ด๋ฃจ์–ด์งˆ ๊ฒƒ์ž„์„ ์•„๋Š” ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•ด์„œ๋Š” ์ฆ‰์‹œ ํ• ๋‹นํ•ด ์ฃผ๋Š” ๊ฒƒ์ด ํ•ฉ๋ฆฌ์ ์ผ ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ์Šคํƒ์˜ ๊ณต๊ฐ„์ด ๋ถ€์กฑํ•˜๋‹ค๋ฉด ์Šคํƒ์„ ์ตœ๋Œ€ 1MB๊นŒ์ง€ ๋Š˜๋ ค ์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ vm_try_handle_fault์—์„œ ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์„๊นŒ? ์ด ๊ฒฝ์šฐ fault๊ฐ€ ๋ฐœ์ƒํ•œ address๋Š” spt์— ์—†์„ ๊ฒƒ์ด๋ผ๋Š” ์‚ฌ์‹ค์„ ์ง์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

bool vm_try_handle_fault(struct intr_frame *f, void *addr, bool user,
                         bool write, bool not_present) {

  struct supplemental_page_table *spt = &thread_current()->spt;
  void *upage = pg_round_down(addr);
  void *curr_rsp = (void *)f->rsp;

  /* Validate stack overflow. */
  if (STACK_LIMIT < addr && addr < spt->stack_bottom) {
    /* If current stack is not full, not a stack overflow. */
    if (curr_rsp != addr) return false;
    /* If stack overflow */
    return vm_stack_growth(upage);
  }
  • if(STACK_LIMIT < addr && addr < spt->stack_bottom && curr_rsp == addr)

์ด๋ฅผ ํ†ตํ•ด ์Šคํƒ์„ ๋Š˜๋ฆฌ๋ ค๋Š” ์‹œ๋„์ž„์„ ์ฒดํฌํ•  ์ˆ˜ ์žˆ๋‹ค. ์Šคํƒ์„ ํ™•์žฅํ•˜๋ ค๊ณ  ํ•˜๋ฉด, rsp๊ฐ’์ด ์Šคํƒ ์˜์—ญ์˜ ๋ฐ–์œผ๋กœ ๊ฐ์†Œํ•œ ๋‹ค์Œ, ํ•ด๋‹น rsp๊ฐ€ ์ฐธ์กฐํ•˜๋Š” ์ฃผ์†Œ์— ์ ‘๊ทผํ•  ๊ฒƒ์ด๋‹ค. ๋”ฐ๋ผ์„œ fault๊ฐ€ ๋ฐœ์ƒํ•œ ์ฃผ์†Œ์™€ rsp๊ฐ’๊ณผ ๊ฐ™๋‹ค๋ฉด, ์œ ํšจํ•œ ์Šคํƒ ํ™•์žฅ ์‹œ๋„๋กœ ๋ณผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. (๊ทธ ์ „์— STACK_LIMIT๊ณผ spt->stack_bottom์„ ๊ธฐ์ค€์œผ๋กœ stack address์ž„์„ ์ฒดํฌํ•˜๊ณ , rsp์™€ ๋น„๊ตํ•˜์—ฌ ์Šคํƒ ํ™•์žฅ ์‹œ๋„์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•œ๋‹ค.)

/* Growing the stack. */
static bool vm_stack_growth(void *addr) {
  /* If addr exceeds STACK_LIMIT, return false. */
  if (addr <= STACK_LIMIT) {
    return false;
  }

  struct supplemental_page_table *spt = &thread_current()->spt;
  spt->stack_bottom = addr;
  return vm_alloc_page(VM_ANON, addr, true);
}

bool vm_alloc_page_with_initializer(enum vm_type type, void *upage,
                                    bool writable, vm_initializer *init,
                                    void *aux) {
    // make page struct and insert spt
    ...
    /* If stack page, claim immediately. */
    if (upage == spt->stack_bottom) {
      if (!vm_do_claim_page(page)) goto err;
    }

vm_alloc_page_with_initializer ํ•จ์ˆ˜๋ฅผ ์Šคํƒ ํŽ˜์ด์ง€์ธ ๊ฒฝ์šฐ ์ฆ‰์‹œ claimํ•˜๋„๋ก ์งœ ๋‘์—ˆ์œผ๋ฏ€๋กœ vm_stack_growth์—์„œ๋Š” spt์˜ stack_bottom ๊ฐ’์„ PGSIZE๋งŒํผ ๋Š˜๋ฆฐ ํ›„ vm_alloc_page๋ฅผ ์ฝœ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

๐Ÿ‘€ ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ์—์„œ๋Š” fault addr๊ฐ€ rsp์™€ ๋‹ค๋ฅธ ์ฃผ์†Œ์ธ ๊ฑฐ ์•„๋ƒ?
int main() {
    char arr[65536]; // 64KB

    arr[0] = 4;
    return 0;
}

๋ฐฐ์—ด์˜ ์›์†Œ๊ฐ€ 4KB๋ฅผ ์ดˆ๊ณผํ•˜๋Š” 65536๊ฐœ ์ด๊ณ , 0๋ฒˆ์งธ ์›์†Œ(๊ฐ€์žฅ ๋‚ฎ์€ ์ฃผ์†Œ)์— ์ ‘๊ทผํ•˜๋ฏ€๋กœ fault address๋Š” rsp + 65536 ์ด ๋˜์ง€ ์•Š์„๊นŒ? ํ•˜์ง€๋งŒ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค.. ์œ„์™€ ๊ฐ™์€ c์ฝ”๋“œ๋ฅผ gcc ์ปดํŒŒ์ผ๋Ÿฌ๋กœ ์ปดํŒŒ์ผํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์ฝ”๋“œ๋ฅผ ๋ฑ‰๋Š”๋‹ค.

main:
.LFB0:
    .cfi_startproc
    endbr64
    pushq    %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    leaq    -61440(%rsp), %r11
.LPSRL0:
    subq    $4096, %rsp
    orq    $0, (%rsp)        // ๐Ÿ”ฅ fault!
    cmpq    %r11, %rsp
    jne    .LPSRL0
    subq    $3976, %rsp
    movb    $4, -65536(%rbp)
    movl    $0, %eax
    leave
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc

.LFB0๋ผ๋ฒจ์˜ ๋งˆ์ง€๋ง‰ ๋ผ์ธ์„ ๋ณด๋ฉด %rsp๊ฐ’์—์„œ 61440๋ฅผ ๋บ€ ๊ฐ’์„ %r11 ๋ ˆ์ง€์Šคํ„ฐ์— ์ €์žฅํ•˜๊ณ  ์žˆ๋‹ค. ์ด๋Š” ๋ฐฐ์—ด์˜ ํฌ๊ธฐ์™€ ๋น„๊ตํ•ด ๋” ๋Š˜๋ ค ์ฃผ์–ด์•ผ ํ•˜๋Š” ์Šคํƒ ์‚ฌ์ด์ฆˆ๋ฅผ ๊ณ„์‚ฐํ•˜๊ณ  ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค. ๊ทธ๋ฆฌ๊ณ , %r11๊ณผ ํ˜„์žฌ %rsp๊ฐ’์„ ๋น„๊ตํ•˜๋ฉด์„œ $4096์”ฉ ์Šคํƒ ์˜์—ญ์„ ๋Š˜๋ ค์ฃผ๊ณ  ์žˆ๋‹ค. ์ด ๋•Œ orq $0, (%rsp) ๋ผ์ธ์— ์˜ํ•ด ์‹ค์ œ์ ์œผ๋กœ ํŽ˜์ด์ง€ ํดํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š”๋ฐ, ์ด๋Š” %rsp๊ฐ’์— ์ ‘๊ทผํ•ด 0๊ณผ์˜ or์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. (0๊ณผ์˜ or์ด๋ฏ€๋กœ ์—ฐ์‚ฐ ๊ฒฐ๊ณผ๋Š” ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. ํดํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋ ค๋Š” ์˜๋„๋กœ ๋ณด์ธ๋‹ค.)

๐Ÿ‘€ ๊ทธ๋Ÿฌ๋ฉด ๋ฐฐ์—ด์„ ์„ ์–ธํ•˜๋ฉด์„œ ์Šคํƒ ์‚ฌ์ด์ฆˆ๋ฅผ ๋Š˜๋ ค์ฃผ๋Š”๋ฐ, ์ด๊ฒƒ์€ ์Šคํƒ์„ lazyํ•˜์ง€ ์•Š๊ฒŒ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€?

lazy load๋Š” ์šด์˜์ฒด์ œ๊ฐ€ ํ•˜๋Š” ์ผ์ด๊ณ , page fault๋ฅผ ์ผ์œผํ‚ค๋ฉด์„œ ์Šคํƒ์„ ๋Š˜๋ ค์ฃผ๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค. ์–ด๋–ป๊ฒŒ ๋ณด๋ฉด, ์šด์˜์ฒด์ œ๊ฐ€ lazy load๋ผ๋Š” ๋ฐฉ์‹์„ ํƒํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์œ ์ € ํ”„๋กœ๊ทธ๋žจ์ด page fault๋ฅผ ๊ณ ์˜์ ์œผ๋กœ ๋ฐœ์ƒ์‹œํ‚ค๋ฉฐ ์Šคํƒ์„ ๋Š˜๋ฆฌ๋„๋ก ์ปดํŒŒ์ผ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

+) ์ด ๋ถ€๋ถ„์— ๋Œ€ํ•œ GPT ์ฝ”๋ฉ˜ํŠธ๋ฅผ ๋‹ฌ์•„๋‘”๋‹ค: ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์Šคํƒ์„ ๋Š˜๋ฆฌ๋Š” ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ด์œ ๋Š” ์Šคํƒ์„ lazyํ•˜๊ฒŒ ํ• ๋‹นํ•˜๋Š” ์šด์˜์ฒด์ œ์™€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. Lazy loading์€ ์šด์˜์ฒด์ œ์—์„œ ํŽ˜์ด์ง€ ํ• ๋‹น์„ ํšจ์œจ์ ์œผ๋กœ ํ•˜๊ธฐ ์œ„ํ•œ ์ „๋žต์ž…๋‹ˆ๋‹ค. ์Šคํƒ ์˜์—ญ์ด ํ™•์žฅ๋˜๋ฉด, ํ”„๋กœ๊ทธ๋žจ์€ ์‹ค์ œ๋กœ ํ•ด๋‹น ์˜์—ญ์— ์ ‘๊ทผํ•  ๋•Œ๊นŒ์ง€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ• ๋‹น๋ฐ›์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ์ ‘๊ทผ์€ ํŽ˜์ด์ง€ ํดํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๊ณ , ์šด์˜์ฒด์ œ๋Š” ๊ทธ ๋•Œ ํŽ˜์ด์ง€๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. (...) lazy loading์€ ์šด์˜์ฒด์ œ์˜ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ด๋Ÿฌํ•œ ์šด์˜์ฒด์ œ์˜ ํŠน์„ฑ์„ ์ด์šฉํ•˜์—ฌ ์Šคํƒ ํ™•์žฅ ์ฝ”๋“œ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ์šด์˜์ฒด์ œ์˜ ํŠน์„ฑ๊ณผ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์˜ ์ตœ์ ํ™” ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

๐Ÿ‘€ ์™œ ํ•œ๋ฒˆ์— 65536๋งŒํผ rsp์—์„œ ๋นผ์ง€ ์•Š๊ณ  4096์”ฉ ๋นผ๋„๋ก ์ปดํŒŒ์ผ๋ ๊นŒ?

์Šคํƒ์€ ์œ„์—์„œ ์•„๋ž˜๋กœ, ํž™์€ ์•„๋ž˜์—์„œ ์œ„๋กœ ํ™•์žฅ๋˜๋ฏ€๋กœ ์ผ๋ฐ˜์ ์ธ ์‚ฌ์šฉ์ž ํ”„๋กœ๊ทธ๋žจ์—์„œ ๋‘ ์˜์—ญ์€ ์ถฉ๋Œํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์Šคํƒ ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ๊ณต๊ฒฉ๊ณผ ๊ฐ™์€ ๋ณด์•ˆ ์œ„ํ˜‘์—์„œ ์Šคํƒ์˜ ํฌ๊ธฐ๊ฐ€ ํž™์„ ์นจ๋ฒ”ํ•˜์—ฌ ๊ณผ๋„ํ•˜๊ฒŒ ํ™•์žฅ๋˜๋ฉด ๋‘ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์ด ์ถฉ๋Œํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Ÿฌํ•œ ๊ณต๊ฒฉ์— ๋Œ€๋น„ํ•˜๊ธฐ ์œ„ํ•ด, ์Šคํƒ์˜ ๋(๊ฐ€์žฅ ๋‚ฎ์€ ์ฃผ์†Œ)์—๋Š” Red Zone ๋˜๋Š” Stack Guard Page๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ๊ฒฝ๊ณ„๊ฐ€ ์กด์žฌํ•œ๋‹ค. ์ด ํŽ˜์ด์ง€๋Š” ์ ‘๊ทผ ๊ธˆ์ง€๋œ ๊ตฌ์—ญ์œผ๋กœ, ํ•ด๋‹น ๊ตฌ์—ญ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด ์‹œ์Šคํ…œ์€ Fault๋ฅผ ๊ฐ์ง€ํ•˜๊ณ  ํ”„๋กœ์„ธ์Šค๋ฅผ ์ข…๋ฃŒ์‹œํ‚จ๋‹ค. (์ฆ‰, ์ด ํŽ˜์ด์ง€์— ๋Œ€ํ•œ ์ ‘๊ทผ์€ ๊ณง ์ž˜๋ชป๋œ ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์œผ๋กœ ์ธ์ง€๋œ๋‹ค.) ๊ทธ๋Ÿฐ๋ฐ ๋งŒ์•ฝ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ํ•œ๋ฒˆ์— ํ”„๋กœ๊ทธ๋žจ์ด ์š”์ฒญํ•œ ๋งŒํผ ์Šคํƒ์„ ํ™•์žฅํ•˜๋„๋ก ์ปดํŒŒ์ผํ•œ๋‹ค๋ฉด ์ด Stack Guard Page๋ฅผ ์Šคํ‚ตํ•œ ์ฃผ์†Œ๊ฐ’์œผ๋กœ rsp๊ฐ€ ์„ค์ •๋  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค. ๋”ฐ๋ผ์„œ ํ•œ ํŽ˜์ด์ง€ ๋‹จ์œ„๋กœ, ๋ฐ˜๋ณต์ ์œผ๋กœ rsp๋ฅผ ๊ฐ์†Œ์‹œํ‚ค๋ฉด์„œ ๊ธˆ์ง€ ๊ตฌ์—ญ์— ์ ‘๊ทผํ•˜๋Š”์ง€๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ปดํŒŒ์ผ๋œ๋‹ค. (-fno-stack-protector ์˜ต์…˜์„ ๋„๋ฉด ์ปดํŒŒ์ผ ๊ฒฐ๊ณผ๊ฐ€ ๋‹ฌ๋ผ์งˆ๊นŒ? ํ™•์ธํ•ด ๋ณผ ๊ฒƒ.)

Red Zone: wikipedia
A closer look at the stack guard page


์—ฌ๊ธฐ๊นŒ์ง€ ๋‹ค ํ–ˆ์œผ๋ฉด, ์ด์ œ์„œ์•ผ 1์ฃผ์ฐจ 2์ฃผ์ฐจ ์ฝ”๋“œ๊ฐ€ ๋ฌผ๋ฆฌ์ ์ธ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ฐ–๊ณ .. ์‹คํ–‰๋˜๊ธฐ ์‹œ์ž‘ํ•œ๋‹ค. ์ด์ œ ๊ฐ ํ”„๋กœ์„ธ์Šค๋Š” ์š”๊ตฌ ํŽ˜์ด์ง•์ด๋ผ๋Š” ํ›Œ๋ฅญํ•œ ์ „๋žต์„ ์‚ฌ์šฉํ•ด ์ „์ฒด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋”์šฑ ํšจ์œจ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค..