1 
2 /* Check that the main thread's stack, on Linux, is automatically
3    extended down to the lowest valid address when a syscall happens.
4    Failure to do so was causing this test to fail on Linux amd64. */
5 
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <assert.h>
10 
11 #include <sys/syscall.h>
12 #include <unistd.h>
13 
14 #define VG_STRINGIFZ(__str)  #__str
15 #define VG_STRINGIFY(__str)  VG_STRINGIFZ(__str)
16 
17 #define __NR_READLINK        VG_STRINGIFY(__NR_readlink)
18 
19 extern long my_readlink ( const char* path );
20 asm(
21 ".text\n"
22 ".globl my_readlink\n"
23 "my_readlink:\n"
24 "\tsubq    $0x1008,%rsp\n"
25 "\tmovq    %rdi,%rdi\n"              // path is in rdi
26 "\tmovq    %rsp,%rsi\n"              // &buf[0] -> rsi
27 "\tmovl    $0x1000,%edx\n"           // sizeof(buf) in rdx
28 "\tmovl    $"__NR_READLINK",%eax\n"  // syscall number
29 "\tsyscall\n"
30 "\taddq    $0x1008,%rsp\n"
31 "\tret\n"
32 ".previous\n"
33 );
34 
recurse(const char * path,long count)35 long recurse ( const char* path, long count )
36 {
37    if (count <= 0) {
38       return my_readlink(path);
39    } else {
40       long r = recurse(path, count-1);
41       return r;
42    }
43 }
44 
main(void)45 int main ( void )
46 {
47    long i, r;
48    for (i = 0; i < 2000; i++) {
49       printf("depth %ld: ", i );
50       r = recurse( "/proc/self", i );
51       if (r > 1) r = 1; /* to make the output repeatable */
52       assert(r >= 1);
53       printf("r = %ld\n", r);
54    }
55    return 0;
56 }
57