title: What is stack guard page and probing stack?
body: <p>I'm analysing how the compiler implements the variable-length array in c99. The following is my c code and disassembly which is commented on my understanding. The code is compiled with &quot;-O3 -fomit-frame-pointer -fno-stack-protector -fpie&quot;</p>
  <p>c code:</p>
  <pre class="lang-c prettyprint-override"><code># include&lt;stdio.h&gt;
  
  int main() {
    size_t sz; // never be signed
    scanf(&quot;%zd&quot;, &amp;sz);
    volatile char s[sz+1]; // prevent to be optimized away.
    s[sz] = '\0';     
  }
  </code></pre>
  <p>disassembly:</p>
  <pre><code>Reading symbols from a.out...
  (gdb) disass main
  Dump of assembler code for function main():
     0x0000000000001060 &lt;+0&gt;:     endbr64                  
     0x0000000000001064 &lt;+4&gt;:     push   %rbp              # save the current frame pointer.
     0x0000000000001065 &lt;+5&gt;:     lea    0xf98(%rip),%rdi  # rdi = &quot;%zd&quot;. 1st param
     0x000000000000106c &lt;+12&gt;:    xor    %eax,%eax         # eax = 0. 
     0x000000000000106e &lt;+14&gt;:    mov    %rsp,%rbp         # set the new frame pointer. 
     0x0000000000001071 &lt;+17&gt;:    sub    $0x10,%rsp        # allocate a 16 bytes. rsp is aligned by 16.
  
     0x0000000000001075 &lt;+21&gt;:    lea    -0x8(%rbp),%rsi              # rsi = &amp;sz. 2nd param.
     0x0000000000001079 &lt;+25&gt;:    callq  0x1050 &lt;__isoc99_scanf@plt&gt;  # call __isoc99_scanf
  
     # volatile char s[sz+1]; // prevent to be optimized away.
     0x000000000000107e &lt;+30&gt;:    mov    -0x8(%rbp),%rcx           # rcx = sz
     0x0000000000001082 &lt;+34&gt;:    mov    %rsp,%rdi                 # rdi = rsp.
     0x0000000000001085 &lt;+37&gt;:    lea    0x10(%rcx),%rax           # rax = sz + 1 + 15
     0x0000000000001089 &lt;+41&gt;:    mov    %rax,%rdx                 # rdx = sz + 1 + 15
     0x000000000000108c &lt;+44&gt;:    and    $0xfffffffffffff000,%rax  # be mutilple of 4096
     0x0000000000001092 &lt;+50&gt;:    sub    %rax,%rdi                 # rdi is the address of the array s
     0x0000000000001095 &lt;+53&gt;:    and    $0xfffffffffffffff0,%rdx  # be multiple of 16 
     0x0000000000001099 &lt;+57&gt;:    mov    %rdi,%rax                 # rax = &amp;s
     0x000000000000109c &lt;+60&gt;:    cmp    %rax,%rsp                 # if sz+16 is less than 4096,
     0x000000000000109f &lt;+63&gt;:    je     0x10b6 &lt;main()+86&gt;        # then jump to main+86 for 
  
     # the stack is grown as page size for every iteration of the loop.
     0x00000000000010a1 &lt;+65&gt;:    sub    $0x1000,%rsp        # grow the stack. 
     0x00000000000010a8 &lt;+72&gt;:    orq    $0x0,0xff8(%rsp)    # probe stack(???).
     0x00000000000010b1 &lt;+81&gt;:    cmp    %rax,%rsp           # if rsp isn't equal to rax,
     0x00000000000010b4 &lt;+84&gt;:    jne    0x10a1 &lt;main()+65&gt;  # then loop.
  
     0x00000000000010b6 &lt;+86&gt;:    and    $0xfff,%edx         # be less than 4096
     0x00000000000010bc &lt;+92&gt;:    sub    %rdx,%rsp           # allocate the remainder.
     0x00000000000010bf &lt;+95&gt;:    test   %rdx,%rdx           # if the remainder is not zero,
     0x00000000000010c2 &lt;+98&gt;:    jne    0x10cc &lt;main()+108&gt; # then, jump to probe stack(?).
  
     0x00000000000010c4 &lt;+100&gt;:   movb   $0x0,(%rsp,%rcx,1)  # s[sz] = '\0'
     0x00000000000010c8 &lt;+104&gt;:   xor    %eax,%eax           # eax = 0. 
     0x00000000000010ca &lt;+106&gt;:   leaveq                     # restore the previous stack frame.
     0x00000000000010cb &lt;+107&gt;:   retq                       # return 0;
  
     0x00000000000010cc &lt;+108&gt;:   orq    $0x0,-0x8(%rsp,%rdx,1)  # probe stack(??).
     0x00000000000010d2 &lt;+114&gt;:   jmp    0x10c4 &lt;main()+100&gt;     # jump back.
  End of assembler dump.
  </code></pre>
  <p>&quot;https://nullprogram.com/blog/2019/10/27/&quot;
  says that first, <code>-fomit-frame-pointer</code> is ignored because VLA have to track the stack-frame dynamically. Second, when <code>-fstack-clash-protection</code> is enabled the compiler generates extra code to probe every pages of allocation in case one of those pages is a guard page, etc..</p>
  <p>But in my disassembly code, I don't understand these lines:</p>
  <pre><code>   # the stack is grown as page size for every iteration of the loop.
     0x00000000000010a1 &lt;+65&gt;:    sub    $0x1000,%rsp        # grow the stack. 
     0x00000000000010a8 &lt;+72&gt;:    orq    $0x0,0xff8(%rsp)    # probe stack(???).
     0x00000000000010b1 &lt;+81&gt;:    cmp    %rax,%rsp           # if rsp isn't equal to rax,
     0x00000000000010b4 &lt;+84&gt;:    jne    0x10a1 &lt;main()+65&gt;  # then loop.
  </code></pre>
  <p>What does &quot;orq $0x0, 0xff8(%rsp)&quot; mean??. and what is probing stack?</p>