刚写了2颗树,里面用到了递归,顺着这个就随便写点关于递归的问题。这些问题都比较初级,也正应了这个blog的名字,当作一个学习和复习问题的笔记罢了。

记得我上学那会,C语言老师讲melloc内存那会就不理解为什么不直接用数组,因为当时不懂的东西太多,也不差这一个,所以也没放在心上。

后来就知道了数组是直接在线程栈上面开辟空间,而melloc则是使用系统堆来分配空间。(当然,这只是一个浅显的理解,操作系统后台的内存分配比这要复杂的多得多,比如windows下面有保留内存、堆和文件映射内存等多种内存分配方式来适应各种大小、类别内存分配的需求,melloc的实现还没有仔细研究过

而线程栈的大小是有限制的,对于我自己使用的x86_64 linux系统,默认是8M(使用ulimit -s来查看),一旦超过了这个大小,程序就直接崩溃了。(这个问题涉及到x86分段机制,比刚才那个问题更加底层)。

因此,对于栈空间的使用一定要非常谨慎。每次递归都会在栈中消耗空间,因此递归的空间复杂度决定了这个递归是不是安全的。

首先,来看看究竟这究竟是怎么一个过程。

先用我微不足道的c语言知识写一个简单的求和的递归程序

int sum(int n)
{
    if(n==1)
        return 1;
    else
        return n+sum(n-1);
}
int main()
{
    int n=5;
    int s;
    s=sum(n);
}


编译并连接,使用objdump -D 来进行反汇编,得到如下结果

rec:     文件格式 elf64-x86-64
Disassembly of section .interp:
0000000000400238 <.interp>:
  400238:   2f                      (bad)
  400239:   6c                      insb   (%dx),%es:(%rdi)
  40023a:   69 62 36 34 2f 6c 64    imul   $0x646c2f34,0x36(%rdx),%esp
  400241:   2d 6c 69 6e 75          sub    $0x756e696c,%eax
  400246:   78 2d                   js     400275 <_init-0x133>
  400248:   78 38                   js     400282 <_init-0x126>
  40024a:   36                      ss
  40024b:   2d 36 34 2e 73          sub    $0x732e3436,%eax
  400250:   6f                      outsl  %ds:(%rsi),(%dx)
  400251:   2e 32 00                xor    %cs:(%rax),%al
Disassembly of section .note.ABI-tag:
0000000000400254 <.note.ABI-tag>:
  400254:   04 00                   add    $0x0,%al
  400256:   00 00                   add    %al,(%rax)
  400258:   10 00                   adc    %al,(%rax)
  40025a:   00 00                   add    %al,(%rax)
  40025c:   01 00                   add    %eax,(%rax)
  40025e:   00 00                   add    %al,(%rax)
  400260:   47                      rex.RXB
  400261:   4e 55                   rex.WRX push %rbp
  400263:   00 00                   add    %al,(%rax)
  400265:   00 00                   add    %al,(%rax)
  400267:   00 02                   add    %al,(%rdx)
  400269:   00 00                   add    %al,(%rax)
  40026b:   00 06                   add    %al,(%rsi)
  40026d:   00 00                   add    %al,(%rax)
  40026f:   00 18                   add    %bl,(%rax)
  400271:   00 00                   add    %al,(%rax)
    ...
Disassembly of section .note.gnu.build-id:
0000000000400274 <.note.gnu.build-id>:
  400274:   04 00                   add    $0x0,%al
  400276:   00 00                   add    %al,(%rax)
  400278:   14 00                   adc    $0x0,%al
  40027a:   00 00                   add    %al,(%rax)
  40027c:   03 00                   add    (%rax),%eax
  40027e:   00 00                   add    %al,(%rax)
  400280:   47                      rex.RXB
  400281:   4e 55                   rex.WRX push %rbp
  400283:   00 78 c1                add    %bh,-0x3f(%rax)
  400286:   f9                      stc
  400287:   a6                      cmpsb  %es:(%rdi),%ds:(%rsi)
  400288:   6f                      outsl  %ds:(%rsi),(%dx)
  400289:   fd                      std
  40028a:   a7                      cmpsl  %es:(%rdi),%ds:(%rsi)
  40028b:   9f                      lahf
  40028c:   dc 12                   fcoml  (%rdx)
  40028e:   a7                      cmpsl  %es:(%rdi),%ds:(%rsi)
  40028f:   b1 d1                   mov    $0xd1,%cl
  400291:   d9 cc                   fxch   %st(4)
  400293:   9f                      lahf
  400294:   dc 2f                   fsubrl (%rdi)
  400296:   d1 13                   rcll   (%rbx)
Disassembly of section .gnu.hash:
0000000000400298 <.gnu.hash>:
  400298:   01 00                   add    %eax,(%rax)
  40029a:   00 00                   add    %al,(%rax)
  40029c:   01 00                   add    %eax,(%rax)
  40029e:   00 00                   add    %al,(%rax)
  4002a0:   01 00                   add    %eax,(%rax)
    ...
Disassembly of section .dynsym:
00000000004002b8 <.dynsym>:
    ...
  4002d0:   0b 00                   or     (%rax),%eax
  4002d2:   00 00                   add    %al,(%rax)
  4002d4:   12 00                   adc    (%rax),%al
    ...
  4002e6:   00 00                   add    %al,(%rax)
  4002e8:   1d 00 00 00 20          sbb    $0x20000000,%eax
    ...
Disassembly of section .dynstr:
0000000000400300 <.dynstr>:
  400300:   00 6c 69 62             add    %ch,0x62(%rcx,%rbp,2)
  400304:   63 2e                   movslq (%rsi),%ebp
  400306:   73 6f                   jae    400377 <_init-0x31>
  400308:   2e 36 00 5f 5f          cs add %bl,%cs:%ss:0x5f(%rdi)
  40030d:   6c                      insb   (%dx),%es:(%rdi)
  40030e:   69 62 63 5f 73 74 61    imul   $0x6174735f,0x63(%rdx),%esp
  400315:   72 74                   jb     40038b <_init-0x1d>
  400317:   5f                      pop    %rdi
  400318:   6d                      insl   (%dx),%es:(%rdi)
  400319:   61                      (bad)
  40031a:   69 6e 00 5f 5f 67 6d    imul   $0x6d675f5f,0x0(%rsi),%ebp
  400321:   6f                      outsl  %ds:(%rsi),(%dx)
  400322:   6e                      outsb  %ds:(%rsi),(%dx)
  400323:   5f                      pop    %rdi
  400324:   73 74                   jae    40039a <_init-0xe>
  400326:   61                      (bad)
  400327:   72 74                   jb     40039d <_init-0xb>
  400329:   5f                      pop    %rdi
  40032a:   5f                      pop    %rdi
  40032b:   00 47 4c                add    %al,0x4c(%rdi)
  40032e:   49                      rex.WB
  40032f:   42                      rex.X
  400330:   43 5f                   rex.XB pop %r15
  400332:   32 2e                   xor    (%rsi),%ch
  400334:   32 2e                   xor    (%rsi),%ch
  400336:   35                      .byte 0x35
    ...
Disassembly of section .gnu.version:
0000000000400338 <.gnu.version>:
  400338:   00 00                   add    %al,(%rax)
  40033a:   02 00                   add    (%rax),%al
    ...
Disassembly of section .gnu.version_r:
0000000000400340 <.gnu.version_r>:
  400340:   01 00                   add    %eax,(%rax)
  400342:   01 00                   add    %eax,(%rax)
  400344:   01 00                   add    %eax,(%rax)
  400346:   00 00                   add    %al,(%rax)
  400348:   10 00                   adc    %al,(%rax)
  40034a:   00 00                   add    %al,(%rax)
  40034c:   00 00                   add    %al,(%rax)
  40034e:   00 00                   add    %al,(%rax)
  400350:   75 1a                   jne    40036c <_init-0x3c>
  400352:   69 09 00 00 02 00       imul   $0x20000,(%rcx),%ecx
  400358:   2c 00                   sub    $0x0,%al
  40035a:   00 00                   add    %al,(%rax)
  40035c:   00 00                   add    %al,(%rax)
    ...
Disassembly of section .rela.dyn:
0000000000400360 <.rela.dyn>:
  400360:   f8                      clc
  400361:   0f 60 00                punpcklbw (%rax),%mm0
  400364:   00 00                   add    %al,(%rax)
  400366:   00 00                   add    %al,(%rax)
  400368:   06                      (bad)
  400369:   00 00                   add    %al,(%rax)
  40036b:   00 02                   add    %al,(%rdx)
    ...
Disassembly of section .rela.plt:
0000000000400378 <.rela.plt>:
  400378:   18 10                   sbb    %dl,(%rax)
  40037a:   60                      (bad)
  40037b:   00 00                   add    %al,(%rax)
  40037d:   00 00                   add    %al,(%rax)
  40037f:   00 07                   add    %al,(%rdi)
  400381:   00 00                   add    %al,(%rax)
  400383:   00 01                   add    %al,(%rcx)
    ...
  40038d:   00 00                   add    %al,(%rax)
  40038f:   00 20                   add    %ah,(%rax)
  400391:   10 60 00                adc    %ah,0x0(%rax)
  400394:   00 00                   add    %al,(%rax)
  400396:   00 00                   add    %al,(%rax)
  400398:   07                      (bad)
  400399:   00 00                   add    %al,(%rax)
  40039b:   00 02                   add    %al,(%rdx)
    ...
Disassembly of section .init:
00000000004003a8 <_init>:
  4003a8:   48 83 ec 08             sub    $0x8,%rsp
  4003ac:   48 8b 05 45 0c 20 00    mov    0x200c45(%rip),%rax        # 600ff8 <_DYNAMIC+0x1d0>
  4003b3:   48 85 c0                test   %rax,%rax
  4003b6:   74 05                   je     4003bd <_init+0x15>
  4003b8:   e8 33 00 00 00          callq  4003f0 <__gmon_start__@plt>
  4003bd:   48 83 c4 08             add    $0x8,%rsp
  4003c1:   c3                      retq
Disassembly of section .plt:
00000000004003d0 <__libc_start_main@plt-0x10>:
  4003d0:   ff 35 32 0c 20 00       pushq  0x200c32(%rip)        # 601008 <_GLOBAL_OFFSET_TABLE_+0x8>
  4003d6:   ff 25 34 0c 20 00       jmpq   *0x200c34(%rip)        # 601010 <_GLOBAL_OFFSET_TABLE_+0x10>
  4003dc:   0f 1f 40 00             nopl   0x0(%rax)
00000000004003e0 <__libc_start_main@plt>:
  4003e0:   ff 25 32 0c 20 00       jmpq   *0x200c32(%rip)        # 601018 <_GLOBAL_OFFSET_TABLE_+0x18>
  4003e6:   68 00 00 00 00          pushq  $0x0
  4003eb:   e9 e0 ff ff ff          jmpq   4003d0 <_init+0x28>
00000000004003f0 <__gmon_start__@plt>:
  4003f0:   ff 25 2a 0c 20 00       jmpq   *0x200c2a(%rip)        # 601020 <_GLOBAL_OFFSET_TABLE_+0x20>
  4003f6:   68 01 00 00 00          pushq  $0x1
  4003fb:   e9 d0 ff ff ff          jmpq   4003d0 <_init+0x28>
Disassembly of section .text:
0000000000400400 <_start>:
  400400:   31 ed                   xor    %ebp,%ebp
  400402:   49 89 d1                mov    %rdx,%r9
  400405:   5e                      pop    %rsi
  400406:   48 89 e2                mov    %rsp,%rdx
  400409:   48 83 e4 f0             and    $0xfffffffffffffff0,%rsp
  40040d:   50                      push   %rax
  40040e:   54                      push   %rsp
  40040f:   49 c7 c0 d0 05 40 00    mov    $0x4005d0,%r8
  400416:   48 c7 c1 40 05 40 00    mov    $0x400540,%rcx
  40041d:   48 c7 c7 18 05 40 00    mov    $0x400518,%rdi
  400424:   e8 b7 ff ff ff          callq  4003e0 <__libc_start_main@plt>
  400429:   f4                      hlt
  40042a:   66 90                   xchg   %ax,%ax
  40042c:   0f 1f 40 00             nopl   0x0(%rax)
0000000000400430 <deregister_tm_clones>:
  400430:   b8 3f 10 60 00          mov    $0x60103f,%eax
  400435:   55                      push   %rbp
  400436:   48 2d 38 10 60 00       sub    $0x601038,%rax
  40043c:   48 83 f8 0e             cmp    $0xe,%rax
  400440:   48 89 e5                mov    %rsp,%rbp
  400443:   77 02                   ja     400447 <deregister_tm_clones+0x17>
  400445:   5d                      pop    %rbp
  400446:   c3                      retq
  400447:   b8 00 00 00 00          mov    $0x0,%eax
  40044c:   48 85 c0                test   %rax,%rax
  40044f:   74 f4                   je     400445 <deregister_tm_clones+0x15>
  400451:   5d                      pop    %rbp
  400452:   bf 38 10 60 00          mov    $0x601038,%edi
  400457:   ff e0                   jmpq   *%rax
  400459:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
0000000000400460 <register_tm_clones>:
  400460:   b8 38 10 60 00          mov    $0x601038,%eax
  400465:   55                      push   %rbp
  400466:   48 2d 38 10 60 00       sub    $0x601038,%rax
  40046c:   48 c1 f8 03             sar    $0x3,%rax
  400470:   48 89 e5                mov    %rsp,%rbp
  400473:   48 89 c2                mov    %rax,%rdx
  400476:   48 c1 ea 3f             shr    $0x3f,%rdx
  40047a:   48 01 d0                add    %rdx,%rax
  40047d:   48 89 c6                mov    %rax,%rsi
  400480:   48 d1 fe                sar    %rsi
  400483:   75 02                   jne    400487 <register_tm_clones+0x27>
  400485:   5d                      pop    %rbp
  400486:   c3                      retq
  400487:   ba 00 00 00 00          mov    $0x0,%edx
  40048c:   48 85 d2                test   %rdx,%rdx
  40048f:   74 f4                   je     400485 <register_tm_clones+0x25>
  400491:   5d                      pop    %rbp
  400492:   bf 38 10 60 00          mov    $0x601038,%edi
  400497:   ff e2                   jmpq   *%rdx
  400499:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
00000000004004a0 <__do_global_dtors_aux>:
  4004a0:   80 3d 91 0b 20 00 00    cmpb   $0x0,0x200b91(%rip)        # 601038 <__TMC_END__>
  4004a7:   75 11                   jne    4004ba <__do_global_dtors_aux+0x1a>
  4004a9:   55                      push   %rbp
  4004aa:   48 89 e5                mov    %rsp,%rbp
  4004ad:   e8 7e ff ff ff          callq  400430 <deregister_tm_clones>
  4004b2:   5d                      pop    %rbp
  4004b3:   c6 05 7e 0b 20 00 01    movb   $0x1,0x200b7e(%rip)        # 601038 <__TMC_END__>
  4004ba:   f3 c3                   repz retq
  4004bc:   0f 1f 40 00             nopl   0x0(%rax)
00000000004004c0 <frame_dummy>:
  4004c0:   48 83 3d 58 09 20 00    cmpq   $0x0,0x200958(%rip)        # 600e20 <__JCR_END__>
  4004c7:   00
  4004c8:   74 1b                   je     4004e5 <frame_dummy+0x25>
  4004ca:   b8 00 00 00 00          mov    $0x0,%eax
  4004cf:   48 85 c0                test   %rax,%rax
  4004d2:   74 11                   je     4004e5 <frame_dummy+0x25>
  4004d4:   55                      push   %rbp
  4004d5:   bf 20 0e 60 00          mov    $0x600e20,%edi
  4004da:   48 89 e5                mov    %rsp,%rbp
  4004dd:   ff d0                   callq  *%rax
  4004df:   5d                      pop    %rbp
  4004e0:   e9 7b ff ff ff          jmpq   400460 <register_tm_clones>
  4004e5:   e9 76 ff ff ff          jmpq   400460 <register_tm_clones>
  4004ea:   66 90                   xchg   %ax,%ax
00000000004004ec <sum>:
  4004ec:   55                      push   %rbp
  4004ed:   48 89 e5                mov    %rsp,%rbp
  4004f0:   48 83 ec 10             sub    $0x10,%rsp
  4004f4:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004f7:   83 7d fc 01             cmpl   $0x1,-0x4(%rbp)
  4004fb:   75 07                   jne    400504 <sum+0x18>
  4004fd:   b8 01 00 00 00          mov    $0x1,%eax
  400502:   eb 12                   jmp    400516 <sum+0x2a>
  400504:   8b 45 fc                mov    -0x4(%rbp),%eax
  400507:   83 e8 01                sub    $0x1,%eax
  40050a:   89 c7                   mov    %eax,%edi
  40050c:   e8 db ff ff ff          callq  4004ec <sum>
  400511:   8b 55 fc                mov    -0x4(%rbp),%edx
  400514:   01 d0                   add    %edx,%eax
  400516:   c9                      leaveq
  400517:   c3                      retq
0000000000400518 <main>:
  400518:   55                      push   %rbp
  400519:   48 89 e5                mov    %rsp,%rbp
  40051c:   48 83 ec 10             sub    $0x10,%rsp
  400520:   c7 45 f8 05 00 00 00    movl   $0x5,-0x8(%rbp)
  400527:   8b 45 f8                mov    -0x8(%rbp),%eax
  40052a:   89 c7                   mov    %eax,%edi
  40052c:   e8 bb ff ff ff          callq  4004ec <sum>
  400531:   89 45 fc                mov    %eax,-0x4(%rbp)
  400534:   c9                      leaveq
  400535:   c3                      retq
  400536:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40053d:   00 00 00
0000000000400540 <__libc_csu_init>:
  400540:   48 89 6c 24 d8          mov    %rbp,-0x28(%rsp)
  400545:   4c 89 64 24 e0          mov    %r12,-0x20(%rsp)
  40054a:   48 8d 2d c7 08 20 00    lea    0x2008c7(%rip),%rbp        # 600e18 <__init_array_end>
  400551:   4c 8d 25 b8 08 20 00    lea    0x2008b8(%rip),%r12        # 600e10 <__frame_dummy_init_array_entry>
  400558:   48 89 5c 24 d0          mov    %rbx,-0x30(%rsp)
  40055d:   4c 89 6c 24 e8          mov    %r13,-0x18(%rsp)
  400562:   4c 89 74 24 f0          mov    %r14,-0x10(%rsp)
  400567:   4c 89 7c 24 f8          mov    %r15,-0x8(%rsp)
  40056c:   48 83 ec 38             sub    $0x38,%rsp
  400570:   4c 29 e5                sub    %r12,%rbp
  400573:   41 89 ff                mov    %edi,%r15d
  400576:   49 89 f6                mov    %rsi,%r14
  400579:   48 c1 fd 03             sar    $0x3,%rbp
  40057d:   49 89 d5                mov    %rdx,%r13
  400580:   31 db                   xor    %ebx,%ebx
  400582:   e8 21 fe ff ff          callq  4003a8 <_init>
  400587:   48 85 ed                test   %rbp,%rbp
  40058a:   74 1a                   je     4005a6 <__libc_csu_init+0x66>
  40058c:   0f 1f 40 00             nopl   0x0(%rax)
  400590:   4c 89 ea                mov    %r13,%rdx
  400593:   4c 89 f6                mov    %r14,%rsi
  400596:   44 89 ff                mov    %r15d,%edi
  400599:   41 ff 14 dc             callq  *(%r12,%rbx,8)
  40059d:   48 83 c3 01             add    $0x1,%rbx
  4005a1:   48 39 eb                cmp    %rbp,%rbx
  4005a4:   75 ea                   jne    400590 <__libc_csu_init+0x50>
  4005a6:   48 8b 5c 24 08          mov    0x8(%rsp),%rbx
  4005ab:   48 8b 6c 24 10          mov    0x10(%rsp),%rbp
  4005b0:   4c 8b 64 24 18          mov    0x18(%rsp),%r12
  4005b5:   4c 8b 6c 24 20          mov    0x20(%rsp),%r13
  4005ba:   4c 8b 74 24 28          mov    0x28(%rsp),%r14
  4005bf:   4c 8b 7c 24 30          mov    0x30(%rsp),%r15
  4005c4:   48 83 c4 38             add    $0x38,%rsp
  4005c8:   c3                      retq
  4005c9:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
00000000004005d0 <__libc_csu_fini>:
  4005d0:   f3 c3                   repz retq
  4005d2:   66 90                   xchg   %ax,%ax
Disassembly of section .fini:
00000000004005d4 <_fini>:
  4005d4:   48 83 ec 08             sub    $0x8,%rsp
  4005d8:   48 83 c4 08             add    $0x8,%rsp
  4005dc:   c3                      retq
Disassembly of section .rodata:
00000000004005e0 <_IO_stdin_used>:
  4005e0:   01 00                   add    %eax,(%rax)
  4005e2:   02 00                   add    (%rax),%al
Disassembly of section .eh_frame_hdr:
00000000004005e4 <.eh_frame_hdr>:
  4005e4:   01 1b                   add    %ebx,(%rbx)
  4005e6:   03 3b                   add    (%rbx),%edi
  4005e8:   38 00                   cmp    %al,(%rax)
  4005ea:   00 00                   add    %al,(%rax)
  4005ec:   06                      (bad)
  4005ed:   00 00                   add    %al,(%rax)
  4005ef:   00 ec                   add    %ch,%ah
  4005f1:   fd                      std
  4005f2:   ff                      (bad)
  4005f3:   ff 84 00 00 00 1c fe    incl   -0x1e40000(%rax,%rax,1)
  4005fa:   ff                      (bad)
  4005fb:   ff 54 00 00             callq  *0x0(%rax,%rax,1)
  4005ff:   00 08                   add    %cl,(%rax)
  400601:   ff                      (bad)
  400602:   ff                      (bad)
  400603:   ff ac 00 00 00 34 ff    ljmpq  *-0xcc0000(%rax,%rax,1)
  40060a:   ff                      (bad)
  40060b:   ff cc                   dec    %esp
  40060d:   00 00                   add    %al,(%rax)
  40060f:   00 5c ff ff             add    %bl,-0x1(%rdi,%rdi,8)
  400613:   ff ec                   ljmpq  *<反汇编器内部错误>
  400615:   00 00                   add    %al,(%rax)
  400617:   00 ec                   add    %ch,%ah
  400619:   ff                      (bad)
  40061a:   ff                      (bad)
  40061b:   ff 14 01                callq  *(%rcx,%rax,1)
    ...
Disassembly of section .eh_frame:
0000000000400620 <__FRAME_END__-0xf0>:
  400620:   14 00                   adc    $0x0,%al
  400622:   00 00                   add    %al,(%rax)
  400624:   00 00                   add    %al,(%rax)
  400626:   00 00                   add    %al,(%rax)
  400628:   01 7a 52                add    %edi,0x52(%rdx)
  40062b:   00 01                   add    %al,(%rcx)
  40062d:   78 10                   js     40063f <_IO_stdin_used+0x5f>
  40062f:   01 1b                   add    %ebx,(%rbx)
  400631:   0c 07                   or     $0x7,%al
  400633:   08 90 01 07 10 14       or     %dl,0x14100701(%rax)
  400639:   00 00                   add    %al,(%rax)
  40063b:   00 1c 00                add    %bl,(%rax,%rax,1)
  40063e:   00 00                   add    %al,(%rax)
  400640:   c0 fd ff                sar    $0xff,%ch
  400643:   ff 2a                   ljmpq  *(%rdx)
    ...
  40064d:   00 00                   add    %al,(%rax)
  40064f:   00 14 00                add    %dl,(%rax,%rax,1)
  400652:   00 00                   add    %al,(%rax)
  400654:   00 00                   add    %al,(%rax)
  400656:   00 00                   add    %al,(%rax)
  400658:   01 7a 52                add    %edi,0x52(%rdx)
  40065b:   00 01                   add    %al,(%rcx)
  40065d:   78 10                   js     40066f <_IO_stdin_used+0x8f>
  40065f:   01 1b                   add    %ebx,(%rbx)
  400661:   0c 07                   or     $0x7,%al
  400663:   08 90 01 00 00 24       or     %dl,0x24000001(%rax)
  400669:   00 00                   add    %al,(%rax)
  40066b:   00 1c 00                add    %bl,(%rax,%rax,1)
  40066e:   00 00                   add    %al,(%rax)
  400670:   60                      (bad)
  400671:   fd                      std
  400672:   ff                      (bad)
  400673:   ff 30                   pushq  (%rax)
  400675:   00 00                   add    %al,(%rax)
  400677:   00 00                   add    %al,(%rax)
  400679:   0e                      (bad)
  40067a:   10 46 0e                adc    %al,0xe(%rsi)
  40067d:   18 4a 0f                sbb    %cl,0xf(%rdx)
  400680:   0b 77 08                or     0x8(%rdi),%esi
  400683:   80 00 3f                addb   $0x3f,(%rax)
  400686:   1a 3b                   sbb    (%rbx),%bh
  400688:   2a 33                   sub    (%rbx),%dh
  40068a:   24 22                   and    $0x22,%al
  40068c:   00 00                   add    %al,(%rax)
  40068e:   00 00                   add    %al,(%rax)
  400690:   1c 00                   sbb    $0x0,%al
  400692:   00 00                   add    %al,(%rax)
  400694:   44 00 00                add    %r8b,(%rax)
  400697:   00 54 fe ff             add    %dl,-0x1(%rsi,%rdi,8)
  40069b:   ff 2c 00                ljmpq  *(%rax,%rax,1)
  40069e:   00 00                   add    %al,(%rax)
  4006a0:   00 41 0e                add    %al,0xe(%rcx)
  4006a3:   10 86 02 43 0d 06       adc    %al,0x60d4302(%rsi)
  4006a9:   67 0c 07                addr32 or $0x7,%al
  4006ac:   08 00                   or     %al,(%rax)
  4006ae:   00 00                   add    %al,(%rax)
  4006b0:   1c 00                   sbb    $0x0,%al
  4006b2:   00 00                   add    %al,(%rax)
  4006b4:   64 00 00                add    %al,%fs:(%rax)
  4006b7:   00 60 fe                add    %ah,-0x2(%rax)
  4006ba:   ff                      (bad)
  4006bb:   ff 1e                   lcallq *(%rsi)
  4006bd:   00 00                   add    %al,(%rax)
  4006bf:   00 00                   add    %al,(%rax)
  4006c1:   41 0e                   rex.B (bad)
  4006c3:   10 86 02 43 0d 06       adc    %al,0x60d4302(%rsi)
  4006c9:   59                      pop    %rcx
  4006ca:   0c 07                   or     $0x7,%al
  4006cc:   08 00                   or     %al,(%rax)
  4006ce:   00 00                   add    %al,(%rax)
  4006d0:   24 00                   and    $0x0,%al
  4006d2:   00 00                   add    %al,(%rax)
  4006d4:   84 00                   test   %al,(%rax)
  4006d6:   00 00                   add    %al,(%rax)
  4006d8:   68 fe ff ff 89          pushq  $0xffffffff89fffffe
  4006dd:   00 00                   add    %al,(%rax)
  4006df:   00 00                   add    %al,(%rax)
  4006e1:   4a 86 06                rex.WX xchg %al,(%rsi)
  4006e4:   8c 05 66 0e 40 83       mov    %es,-0x7cbff19a(%rip)        # ffffffff83801550 <_end+0xffffffff83200510>
  4006ea:   07                      (bad)
  4006eb:   8d 04 8e                lea    (%rsi,%rcx,4),%eax
  4006ee:   03 8f 02 02 58 0e       add    0xe580202(%rdi),%ecx
  4006f4:   08 00                   or     %al,(%rax)
  4006f6:   00 00                   add    %al,(%rax)
  4006f8:   14 00                   adc    $0x0,%al
  4006fa:   00 00                   add    %al,(%rax)
  4006fc:   ac                      lods   %ds:(%rsi),%al
  4006fd:   00 00                   add    %al,(%rax)
  4006ff:   00 d0                   add    %dl,%al
  400701:   fe                      (bad)
  400702:   ff                      (bad)
  400703:   ff 02                   incl   (%rdx)
    ...
0000000000400710 <__FRAME_END__>:
  400710:   00 00                   add    %al,(%rax)
    ...
Disassembly of section .init_array:
0000000000600e10 <__frame_dummy_init_array_entry>:
  600e10:   c0 04 40 00             rolb   $0x0,(%rax,%rax,2)
  600e14:   00 00                   add    %al,(%rax)
    ...
Disassembly of section .fini_array:
0000000000600e18 <__do_global_dtors_aux_fini_array_entry>:
  600e18:   a0                      .byte 0xa0
  600e19:   04 40                   add    $0x40,%al
  600e1b:   00 00                   add    %al,(%rax)
  600e1d:   00 00                   add    %al,(%rax)
    ...
Disassembly of section .jcr:
0000000000600e20 <__JCR_END__>:
    ...
Disassembly of section .dynamic:
0000000000600e28 <_DYNAMIC>:
  600e28:   01 00                   add    %eax,(%rax)
  600e2a:   00 00                   add    %al,(%rax)
  600e2c:   00 00                   add    %al,(%rax)
  600e2e:   00 00                   add    %al,(%rax)
  600e30:   01 00                   add    %eax,(%rax)
  600e32:   00 00                   add    %al,(%rax)
  600e34:   00 00                   add    %al,(%rax)
  600e36:   00 00                   add    %al,(%rax)
  600e38:   0c 00                   or     $0x0,%al
  600e3a:   00 00                   add    %al,(%rax)
  600e3c:   00 00                   add    %al,(%rax)
  600e3e:   00 00                   add    %al,(%rax)
  600e40:   a8 03                   test   $0x3,%al
  600e42:   40 00 00                add    %al,(%rax)
  600e45:   00 00                   add    %al,(%rax)
  600e47:   00 0d 00 00 00 00       add    %cl,0x0(%rip)        # 600e4d <_DYNAMIC+0x25>
  600e4d:   00 00                   add    %al,(%rax)
  600e4f:   00 d4                   add    %dl,%ah
  600e51:   05 40 00 00 00          add    $0x40,%eax
  600e56:   00 00                   add    %al,(%rax)
  600e58:   19 00                   sbb    %eax,(%rax)
  600e5a:   00 00                   add    %al,(%rax)
  600e5c:   00 00                   add    %al,(%rax)
  600e5e:   00 00                   add    %al,(%rax)
  600e60:   10 0e                   adc    %cl,(%rsi)
  600e62:   60                      (bad)
  600e63:   00 00                   add    %al,(%rax)
  600e65:   00 00                   add    %al,(%rax)
  600e67:   00 1b                   add    %bl,(%rbx)
  600e69:   00 00                   add    %al,(%rax)
  600e6b:   00 00                   add    %al,(%rax)
  600e6d:   00 00                   add    %al,(%rax)
  600e6f:   00 08                   add    %cl,(%rax)
  600e71:   00 00                   add    %al,(%rax)
  600e73:   00 00                   add    %al,(%rax)
  600e75:   00 00                   add    %al,(%rax)
  600e77:   00 1a                   add    %bl,(%rdx)
  600e79:   00 00                   add    %al,(%rax)
  600e7b:   00 00                   add    %al,(%rax)
  600e7d:   00 00                   add    %al,(%rax)
  600e7f:   00 18                   add    %bl,(%rax)
  600e81:   0e                      (bad)
  600e82:   60                      (bad)
  600e83:   00 00                   add    %al,(%rax)
  600e85:   00 00                   add    %al,(%rax)
  600e87:   00 1c 00                add    %bl,(%rax,%rax,1)
  600e8a:   00 00                   add    %al,(%rax)
  600e8c:   00 00                   add    %al,(%rax)
  600e8e:   00 00                   add    %al,(%rax)
  600e90:   08 00                   or     %al,(%rax)
  600e92:   00 00                   add    %al,(%rax)
  600e94:   00 00                   add    %al,(%rax)
  600e96:   00 00                   add    %al,(%rax)
  600e98:   f5                      cmc
  600e99:   fe                      (bad)
  600e9a:   ff 6f 00                ljmpq  *0x0(%rdi)
  600e9d:   00 00                   add    %al,(%rax)
  600e9f:   00 98 02 40 00 00       add    %bl,0x4002(%rax)
  600ea5:   00 00                   add    %al,(%rax)
  600ea7:   00 05 00 00 00 00       add    %al,0x0(%rip)        # 600ead <_DYNAMIC+0x85>
  600ead:   00 00                   add    %al,(%rax)
  600eaf:   00 00                   add    %al,(%rax)
  600eb1:   03 40 00                add    0x0(%rax),%eax
  600eb4:   00 00                   add    %al,(%rax)
  600eb6:   00 00                   add    %al,(%rax)
  600eb8:   06                      (bad)
  600eb9:   00 00                   add    %al,(%rax)
  600ebb:   00 00                   add    %al,(%rax)
  600ebd:   00 00                   add    %al,(%rax)
  600ebf:   00 b8 02 40 00 00       add    %bh,0x4002(%rax)
  600ec5:   00 00                   add    %al,(%rax)
  600ec7:   00 0a                   add    %cl,(%rdx)
  600ec9:   00 00                   add    %al,(%rax)
  600ecb:   00 00                   add    %al,(%rax)
  600ecd:   00 00                   add    %al,(%rax)
  600ecf:   00 38                   add    %bh,(%rax)
  600ed1:   00 00                   add    %al,(%rax)
  600ed3:   00 00                   add    %al,(%rax)
  600ed5:   00 00                   add    %al,(%rax)
  600ed7:   00 0b                   add    %cl,(%rbx)
  600ed9:   00 00                   add    %al,(%rax)
  600edb:   00 00                   add    %al,(%rax)
  600edd:   00 00                   add    %al,(%rax)
  600edf:   00 18                   add    %bl,(%rax)
  600ee1:   00 00                   add    %al,(%rax)
  600ee3:   00 00                   add    %al,(%rax)
  600ee5:   00 00                   add    %al,(%rax)
  600ee7:   00 15 00 00 00 00       add    %dl,0x0(%rip)        # 600eed <_DYNAMIC+0xc5>
    ...
  600ef5:   00 00                   add    %al,(%rax)
  600ef7:   00 03                   add    %al,(%rbx)
    ...
  600f01:   10 60 00                adc    %ah,0x0(%rax)
  600f04:   00 00                   add    %al,(%rax)
  600f06:   00 00                   add    %al,(%rax)
  600f08:   02 00                   add    (%rax),%al
  600f0a:   00 00                   add    %al,(%rax)
  600f0c:   00 00                   add    %al,(%rax)
  600f0e:   00 00                   add    %al,(%rax)
  600f10:   30 00                   xor    %al,(%rax)
  600f12:   00 00                   add    %al,(%rax)
  600f14:   00 00                   add    %al,(%rax)
  600f16:   00 00                   add    %al,(%rax)
  600f18:   14 00                   adc    $0x0,%al
  600f1a:   00 00                   add    %al,(%rax)
  600f1c:   00 00                   add    %al,(%rax)
  600f1e:   00 00                   add    %al,(%rax)
  600f20:   07                      (bad)
  600f21:   00 00                   add    %al,(%rax)
  600f23:   00 00                   add    %al,(%rax)
  600f25:   00 00                   add    %al,(%rax)
  600f27:   00 17                   add    %dl,(%rdi)
  600f29:   00 00                   add    %al,(%rax)
  600f2b:   00 00                   add    %al,(%rax)
  600f2d:   00 00                   add    %al,(%rax)
  600f2f:   00 78 03                add    %bh,0x3(%rax)
  600f32:   40 00 00                add    %al,(%rax)
  600f35:   00 00                   add    %al,(%rax)
  600f37:   00 07                   add    %al,(%rdi)
  600f39:   00 00                   add    %al,(%rax)
  600f3b:   00 00                   add    %al,(%rax)
  600f3d:   00 00                   add    %al,(%rax)
  600f3f:   00 60 03                add    %ah,0x3(%rax)
  600f42:   40 00 00                add    %al,(%rax)
  600f45:   00 00                   add    %al,(%rax)
  600f47:   00 08                   add    %cl,(%rax)
  600f49:   00 00                   add    %al,(%rax)
  600f4b:   00 00                   add    %al,(%rax)
  600f4d:   00 00                   add    %al,(%rax)
  600f4f:   00 18                   add    %bl,(%rax)
  600f51:   00 00                   add    %al,(%rax)
  600f53:   00 00                   add    %al,(%rax)
  600f55:   00 00                   add    %al,(%rax)
  600f57:   00 09                   add    %cl,(%rcx)
  600f59:   00 00                   add    %al,(%rax)
  600f5b:   00 00                   add    %al,(%rax)
  600f5d:   00 00                   add    %al,(%rax)
  600f5f:   00 18                   add    %bl,(%rax)
  600f61:   00 00                   add    %al,(%rax)
  600f63:   00 00                   add    %al,(%rax)
  600f65:   00 00                   add    %al,(%rax)
  600f67:   00 fe                   add    %bh,%dh
  600f69:   ff                      (bad)
  600f6a:   ff 6f 00                ljmpq  *0x0(%rdi)
  600f6d:   00 00                   add    %al,(%rax)
  600f6f:   00 40 03                add    %al,0x3(%rax)
  600f72:   40 00 00                add    %al,(%rax)
  600f75:   00 00                   add    %al,(%rax)
  600f77:   00 ff                   add    %bh,%bh
  600f79:   ff                      (bad)
  600f7a:   ff 6f 00                ljmpq  *0x0(%rdi)
  600f7d:   00 00                   add    %al,(%rax)
  600f7f:   00 01                   add    %al,(%rcx)
  600f81:   00 00                   add    %al,(%rax)
  600f83:   00 00                   add    %al,(%rax)
  600f85:   00 00                   add    %al,(%rax)
  600f87:   00 f0                   add    %dh,%al
  600f89:   ff                      (bad)
  600f8a:   ff 6f 00                ljmpq  *0x0(%rdi)
  600f8d:   00 00                   add    %al,(%rax)
  600f8f:   00 38                   add    %bh,(%rax)
  600f91:   03 40 00                add    0x0(%rax),%eax
    ...
Disassembly of section .got:
0000000000600ff8 <.got>:
    ...
Disassembly of section .got.plt:
0000000000601000 <_GLOBAL_OFFSET_TABLE_>:
  601000:   28 0e                   sub    %cl,(%rsi)
  601002:   60                      (bad)
    ...
  601017:   00 e6                   add    %ah,%dh
  601019:   03 40 00                add    0x0(%rax),%eax
  60101c:   00 00                   add    %al,(%rax)
  60101e:   00 00                   add    %al,(%rax)
  601020:   f6 03 40                testb  $0x40,(%rbx)
  601023:   00 00                   add    %al,(%rax)
  601025:   00 00                   add    %al,(%rax)
    ...
Disassembly of section .data:
0000000000601028 <__data_start>:
    ...
0000000000601030 <__dso_handle>:
    ...
Disassembly of section .bss:
0000000000601038 <__bss_start>:
    ...
Disassembly of section .comment:
0000000000000000 <.comment>:
   0:   47                      rex.RXB
   1:   43                      rex.XB
   2:   43 3a 20                rex.XB cmp (%r8),%spl
   5:   28 55 62                sub    %dl,0x62(%rbp)
   8:   75 6e                   jne    78 <_init-0x400330>
   a:   74 75                   je     81 <_init-0x400327>
   c:   2f                      (bad)
   d:   4c 69 6e 61 72 6f 20    imul   $0x34206f72,0x61(%rsi),%r13
  14:   34
  15:   2e                      cs
  16:   37                      (bad)
  17:   2e 33 2d 31 75 62 75    xor    %cs:0x75627531(%rip),%ebp        # 7562754f <_end+0x7502650f>
  1e:   6e                      outsb  %ds:(%rsi),(%dx)
  1f:   74 75                   je     96 <_init-0x400312>
  21:   31 29                   xor    %ebp,(%rcx)
  23:   20 34 2e                and    %dh,(%rsi,%rbp,1)
  26:   37                      (bad)
  27:   2e 33 00                xor    %cs:(%rax),%eax


好家伙,这么几行简单的代码变成了这么一堆,看来连接器帮我们做了好多东西,我们不去管他,只挑其中我们自己写的部分来看。虽然at&t汇编和intel汇编格式不一样,但基本上是一一对应的,能够猜出究竟是在干什么。

00000000004004ec <sum>:
  4004ec:   55                      push   %rbp
  4004ed:   48 89 e5                mov    %rsp,%rbp
  4004f0:   48 83 ec 10             sub    $0x10,%rsp
  4004f4:   89 7d fc                mov    %edi,-0x4(%rbp)
  4004f7:   83 7d fc 01             cmpl   $0x1,-0x4(%rbp)
  4004fb:   75 07                   jne    400504 <sum+0x18>
  4004fd:   b8 01 00 00 00          mov    $0x1,%eax
  400502:   eb 12                   jmp    400516 <sum+0x2a>
  400504:   8b 45 fc                mov    -0x4(%rbp),%eax
  400507:   83 e8 01                sub    $0x1,%eax
  40050a:   89 c7                   mov    %eax,%edi
  40050c:   e8 db ff ff ff          callq  4004ec <sum>
  400511:   8b 55 fc                mov    -0x4(%rbp),%edx
  400514:   01 d0                   add    %edx,%eax
  400516:   c9                      leaveq
  400517:   c3                      retq
0000000000400518 <main>:
  400518:   55                      push   %rbp
  400519:   48 89 e5                mov    %rsp,%rbp
  40051c:   48 83 ec 10             sub    $0x10,%rsp
  400520:   c7 45 f8 05 00 00 00    movl   $0x5,-0x8(%rbp)
  400527:   8b 45 f8                mov    -0x8(%rbp),%eax
  40052a:   89 c7                   mov    %eax,%edi
  40052c:   e8 bb ff ff ff          callq  4004ec <sum>
  400531:   89 45 fc                mov    %eax,-0x4(%rbp)
  400534:   c9                      leaveq
  400535:   c3                      retq
  400536:   66 2e 0f 1f 84 00 00    nopw   %cs:0x0(%rax,%rax,1)
  40053d:   00 00 00

一个sum函数,一个main函数。

main函数通过call sum的地址来调用sum函数,sum同样通过call这个地址来调用自身。

过程是一样的,我们就从sum函数还是分析。

每当进入调用函数的时候,被调用者首先push %rbp,mov %rsp to %rbp的方式来将调用栈的基地址保存起来。其中rbp,和rsp就是64位版本的ebp和esp。bp里面存放的当前栈的栈底,而sp存放当前栈的栈顶。刚进入一个新函数,需要把调用者的栈顶变成自己的栈底,于是就要把调用者的栈底地址保存起来,放在自己的栈底。这就是头两条指令的意义。注意一下顺序,push在前,说明当前的栈桢不包含调用者的基地址。

接下来sub $0x10,%rsp是做什么的呢?

从字面意义理解,这条指令的作用是将rsp减少了16字节,对于一个子长为8字节的64位系统来说,这就是两个字的大小。在x86平台上,栈生长的方向是倒生长,也就是说栈底在高地址,而栈顶则是底地址。(这个设计和小端字节序一样让人蛋疼)因此rsp减掉0x10就相当于把栈抬高了2个字。这两个字就是用来保存一些东西,但是现在还不知道该保存什么,所以先把这些空间保留出来。究竟这个空间是用来做什么的,过一会再解释。另外,这个操作解释了为什么c语言要声明变量类型,因为刚进入函数,程序的主体部分还没有运行的时候,编译器需要知道一共需要保留多大的空间。

再接下来的两条指令,先把edi寄存器的值放到比当前栈低高4的地方。再把它和0x1比较,根据我们的程序,可以猜到这里面放的就是变量n。edi寄存器里面保存的就是当前n的值需要注意的是,edi是一个32位寄存器,所以在我们这个64位的系统中,int类型的大小还是4个字节。而栈又是倒生长的,这个方法是没问题的,可以自行在脑中想象这时候栈的样子。紧贴栈底的是我们函数中定义的局部变量。不过我们申请了2个字的长度,栈中保留的空间还有12个字节。

接下来根据这个比较的结果选择跳转到400504的mov -0x4(%rbp),%eax这条指令上,或者是把eax-1并跳转到400516的leaveq这条指令的地址上。

leave的作用等同于move ebp to esp,pop ebp,也就是我们刚进入函数那两个操作的逆操作,把栈底变成栈顶,再上一个栈顶保存好的原来的ebp的值还原到ebp寄存器,完成了栈帧的切换。之后的return让程序跳转到调用之前的地址的下一个地址。这个地址在哪里?

了解一下ret的是怎么执行的。首先,在执行ret操作的时候,会先把下一个要执行的指令地址pop到ip寄存器里面,而这个地址就是函数调用者在调用函数之前,push进栈的。

这样,刚才保留的地址中,就又有一个是为call指令预留的函数返回后下一个要执行的地址。这个地址会占据8个字节。还有4个字节干什么去了?

因为我的机器是一个64位系统,字长为8字节,但是内存访问为了增加速度,都是采用字对齐的方式。剩下那4个字节,都是为了字对齐而浪费掉了。因此,在保留的空间中,局部变量之后保存的是要调用的函数的返回地址。

我们刚看到了函数返回的过程,再来看看另一个分支是怎样进行递归调用的。

首先,根据rbp访问到保存好的局部变量n,把它送到eax寄存器,再把eax-1于是这时候eax代表了n-1,再把eax送到edi,变成edi表示n-1,我开始递归,等到递归结束后,我们把当前n的值送到edx,再把eax和edx相加,结果送到eax。因为eax每次递归都会用到。假设我们再最后一次递归调用中,也就是n=1的时候,eax在相加之前等于0,edx=1.因此eax=eax+edx的意义就是1=1+0,也就是上一次递归的结果。再上一层就变成了eax=1+1=2,再上一层就是eax=2+1=3,以此类推,可以得到结论:

add %edx,%eax的意思就是f(n)=f(n-1)+n。其中,eax代表了下一层函数的返回值,而edx代表了这层函数的n。因为eax是全部递归的公用变量,而edx则是保存在当前栈中的。局部变量n,也就是-0x4(%rbp)的值是放在edi寄存器中传过来的,所以edi表示了当前函数的参数。十分精妙。

另外,函数参数除了通过寄存器传入,还可以通过堆栈传入。不同语言,不同系统,不同编译参数不一样。当前这种叫做fastcall调用。_cdecl和stdcall更为常见一些,对这些问题,我没什么研究,只是有点了解。

总之,假设参数不入栈,对于每次递归,消耗的空间至少有3个部分,局部变量,将要调用的函数的返回地址和当前栈帧的栈底的指针。对于这个sum函数来说,一共24个字节。

因为栈是倒生长的,而数组是正生长的。如果局部变量是一个数组,那么使劲向这个数组塞东西会毁掉上一个栈的内容,可以把返回地址所在的地方填成自己想要的地址。这就是缓冲区溢出的原理。以前的做法是把想要执行的代码的指令当成数据传进去,修改返回地址的指针,函数返回的时候就开始运行自己的指令。后来操作系统不让非代码段的程序运行,又针对这个对策有有新的办法。了解的不多,不过感觉挺好玩的