C程序运行过程中堆栈结构分析-Linux 64位系统

64/32位Linux系统的差异(地址空间布局,系统调用)对比分析 映射地址:可以看到,对应的地址0x7fd9b8c00000是PSE页,映射了10M,是PMD级的大页映射,也就是2M页面的映射。连续影射了5个PMD大页。这些大页的分配是在mmap后,执行memset(addr, 0x5a, ...)时通过page fault流程进行分配的,对应执行hugetlb_fault的执行流程。 阅读详情
  // C函数调用堆栈结构分析例程
  // 测试环境:平台ubuntu 14.04_3 64位 GCC Ubuntu 4.8.5-2
  1 #include <stdio.h>                                                                                                                                  
  2 int add(int m, int n)
  3 {
  4     int x;
  5     x = 100;
  6     return x+m+n;
  7 }
  8 int sum(int a, int b, int c, int d, int e, int f)
  9 {
 10     int a1,a2,a3,a4,a5,a6;
 11     a1 = 10;
 12     a2 = 20;
 13     a3 = 30;
 14     a4 = 40;
 15     a5 = 50;
 16     a6 = 60;
 17     return add(a1,a2)+a3+a4+a5+a6+a+b+c+d+e+f;
 18 }
 19
 20 int main()
 21 {
 22     int x1,x2,x3,x4,sum_of;
 23     x1 = 1;
 24     x2 = 2;
 25     x3 = 3;
 26     x4 = 4;
 27     sum_of = sum(x1,x2,x3,x4,5,6);
 28     return 0;
 29 }

//对应的汇编语言程序

0x4004ed <add>            push   %rbp                // bp值压栈
0x4004ee <add+1>        mov    %rsp,%rbp            //当前sp->bp
0x4004f1 <add+4>        mov    %edi,-0x4(%rbp)    //第一实参存储紧邻栈顶
0x4004f4 <add+7>        mov    %esi,-0x8(%rbp)    //第二实参存储
0x4004f7 <add+10>        mov    -0x8(%rbp),%eax    //完成运算
0x4004fa <add+13>        mov    -0x4(%rbp),%edx
0x4004fd <add+16>        add    %edx,%eax
0x4004ff <add+18>        pop    %rbp                //恢复bp
0x400500 <add+19>        retq                        //函数返回 返回值通过eax
0x400501 <sum>            push   %rbp                // bp值压栈
0x400502 <sum+1>        mov    %rsp,%rbp            //当前sp->bp
0x400505 <sum+4>        sub    $0x38,%rsp //根据函数参数及内部变量数调整栈顶指针
0x400509 <sum+8>        mov    %edi,-0x24(%rbp)    //第一实参存储紧邻内部变量
0x40050c <sum+11>        mov    %esi,-0x28(%rbp)     //第二实参存储紧邻内部变量
0x40050f <sum+14>        mov    %edx,-0x2c(%rbp)     //第三实参存储
0x400512 <sum+17>        mov    %ecx,-0x30(%rbp)     //第四实参存储
0x400515 <sum+20>        mov    %r8d,-0x34(%rbp)     //第五实参存储
0x400519 <sum+24>        mov    %r9d,-0x38(%rbp)     //第六实参存储
0x40051d <sum+28>        movl   $0xa,-0x18(%rbp)    //第一个内部变量赋值
0x400524 <sum+35>        movl   $0x14,-0x14(%rbp)     //第二个内部变量赋值
0x40052b <sum+42>        movl   $0x1e,-0x10(%rbp)     //第三个内部变量赋值
0x400532 <sum+49>        movl   $0x28,-0xc(%rbp)     //第四个内部变量赋值
0x400539 <sum+56>        movl   $0x32,-0x8(%rbp)     //第五个内部变量赋值
0x400540 <sum+63>        movl   $0x3c,-0x4(%rbp)     //第六个内部变量赋值
0x400547 <sum+70>        mov    -0x14(%rbp),%edx    //为add函数调用准备参数传递
0x40054a <sum+73>        mov    -0x18(%rbp),%eax    //本编译器通过寄存器传参
0x40054d <sum+76>        mov    %edx,%esi
0x40054f <sum+78>        mov    %eax,%edi
0x400551 <sum+80>        callq  0x4004ed <add>
0x400556 <sum+85>        mov    -0x10(%rbp),%edx
0x400559 <sum+88>        add    %eax,%edx            //函数返回值有eax传递
0x40055b <sum+90>        mov    -0xc(%rbp),%eax
0x40055e <sum+93>        add    %eax,%edx
0x400560 <sum+95>        mov    -0x8(%rbp),%eax
0x400563 <sum+98>        add    %eax,%edx
0x400565 <sum+100>        mov    -0x4(%rbp),%eax
0x400568 <sum+103>        add    %eax,%edx
0x40056a <sum+105>        mov    -0x24(%rbp),%eax
0x40056d <sum+108>        add    %eax,%edx
0x40056f <sum+110>        mov    -0x28(%rbp),%eax
0x400572 <sum+113>        add    %eax,%edx
0x400574 <sum+115>        mov    -0x2c(%rbp),%eax
0x400577 <sum+118>        add    %eax,%edx
0x400579 <sum+120>        mov    -0x30(%rbp),%eax
0x40057c <sum+123>        add    %eax,%edx
0x40057e <sum+125>        mov    -0x34(%rbp),%eax
0x400581 <sum+128>        add    %eax,%edx
0x400583 <sum+130>        mov    -0x38(%rbp),%eax
0x400586 <sum+133>        add    %edx,%eax
0x400588 <sum+135>        leaveq
0x400589 <sum+136>        retq                        //函数返回
0x40058a <main>            push   %rbp                // bp值压栈
0x40058b <main+1>        mov    %rsp,%rbp            //当前sp->bp
0x40058e <main+4>        sub    $0x20,%rsp //根据函数参数及内部变量数调整栈顶指针
0x400592 <main+8>        movl   $0x1,-0x14(%rbp)    //第一个内部变量赋值
0x400599 <main+15>        movl   $0x2,-0x10(%rbp)    //第二个内部变量赋值
0x4005a0 <main+22>        movl   $0x3,-0xc(%rbp)    //第三个内部变量赋值
0x4005a7 <main+29>        movl   $0x4,-0x8(%rbp)    //第四个内部变量赋值
0x4005ae <main+36>        mov    -0x8(%rbp),%ecx    //为sum函数调用准备参数
0x4005b1 <main+39>        mov    -0xc(%rbp),%edx
0x4005b4 <main+42>        mov    -0x10(%rbp),%esi
0x4005b7 <main+45>        mov    -0x14(%rbp),%eax
0x4005ba <main+48>        mov    $0x6,%r9d
0x4005c0 <main+54>        mov    $0x5,%r8d
0x4005c6 <main+60>        mov    %eax,%edi
0x4005c8 <main+62>        callq  0x400501 <sum>
0x4005cd <main+67>        mov    %eax,-0x4(%rbp)
0x4005d0 <main+70>        mov    $0x0,%eax
0x4005d5 <main+75>        leaveq
0x4005d6 <main+76>        retq
0x4005d7                    nopw   0x0(%rax,%rax,1)
0x4005e0 <__libc_csu_init>    push   %r15
              
(gdb) b main
Breakpoint 1 at 0x400592: file test.c, line 21.
(gdb) display $rsp        //监测sp的值
(gdb) display $rbp        //监测bp的值
(gdb) display $rip        //监测ip的值
(gdb) layout asm        //显示汇编语句窗口
(gdb)r                     //运行程序
Starting program: /home/cmaxd/src/4-1/test
Breakpoint 1, main () at test.c:21
21        x1 = 1;

(gdb)si                    //指令级单步执行
3: $rip = (void (*)()) 0x400592 <main+8>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00:    0xf63d4e2e    0x00000000    0x0040030b    0x00000000
0x7fffffffdc10:    0xffffffff    0x00000000    0xffffdd78    0x00007fff
0x7fffffffdc20:    0xf7a211f8    0x00007fff    0xf7fe2000    0x00007fff
0x7fffffffdc30:    0xf7ffe1c8    0x00007fff    0x00000000    0x00000000
0x7fffffffdc40:    0x00000001    0x00000000    0x0040062d    0x00000000
0x7fffffffdc50:    0xffffdc80    0x00007fff    0x00000000    0x00000000
0x7fffffffdc60:    0x004005e0    0x00000000    0x00400400    0x00000000
0x7fffffffdc70:    0xffffdd60    0x00007fff    0x00000000    0x00000000
0x7fffffffdc80:    0x00000000    0x00000000    0xf7a32f45    0x00007fff

//以下完成main函数内部变量x1~x4的赋值,x1~x4的存储空间分配在栈中
(gdb) si
3: $rip = (void (*)()) 0x400599 <main+15>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005a0 <main+22>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005a7 <main+29>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
(gdb) si
3: $rip = (void (*)()) 0x4005ae <main+36>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60

(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00:    0xf63d4e2e    0x00000000    0x0040030b    0x00000000
0x7fffffffdc10:    0xffffffff    0x00000000    0xffffdd78    0x00007fff
0x7fffffffdc20:    0xf7a211f8    0x00007fff    0xf7fe2000    0x00007fff
0x7fffffffdc30:    0xf7ffe1c8    0x00007fff    0x00000000    0x00000000
0x7fffffffdc40:    0x00000001    0x00000000    0x0040062d    0x00000000
0x7fffffffdc50:    0xffffdc80    0x00007fff    0x00000000    0x00000000
0x7fffffffdc60:    0x004005e0    0x00000000    0x00400400    0x00000001
0x7fffffffdc70:    0x00000002    0x00000003    0x00000004    0x00000000
0x7fffffffdc80:    0x00000000    0x00000000    0xf7a32f45    0x00007fff
(gdb) si 7
3: $rip = (void (*)()) 0x4005c8 <main+62>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//这段程序完成sum函数调用前的参数准备
//参数传递顺序为 第一个参数->edi, 第二个参数->esi,第三个参数->edx,第四个参数->ecx,第五个参数->r8,第六个参数->r9
(gdb) info reg
rax            0x1      1
rbx            0x0      0
rcx            0x4      4
rdx            0x3      3
rsi            0x2      2
rdi            0x1      1
rbp            0x7fffffffdc80   0x7fffffffdc80
rsp            0x7fffffffdc60   0x7fffffffdc60
r8             0x5      5
r9             0x6      6
r10            0x7fffffffdb10   140737488345872
r11            0x7ffff7a32e50   140737348054608
r12            0x400400 4195328
r13            0x7fffffffdd60   140737488346464
r14            0x0      0
r15            0x0      0
rip            0x4005c8 0x4005c8 <main+62>
eflags         0x206    [ PF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0
(gdb) si
sum (a=32767, b=-134340608, c=32767, d=-140373512, e=32767, f=-8840) at test.c:7
3: $rip = (void (*)()) 0x400501 <sum>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc58
//系统自动完成函数返回地址的压栈,为sum函数调用作准备
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e      0x00000000      0x0040030b      0x00000000
0x7fffffffdc10: 0xffffffff      0x00000000      0xffffdd78      0x00007fff
0x7fffffffdc20: 0xf7a211f8      0x00007fff      0xf7fe2000      0x00007fff
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x00000000      0x00000000
0x7fffffffdc40: 0x00000001      0x00000000      0x0040062d      0x00000000
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x00000000
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff

(gdb) si
3: $rip = (void (*)()) 0x400502 <sum+1>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc50
//bp入栈
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e      0x00000000      0x0040030b      0x00000000
0x7fffffffdc10: 0xffffffff      0x00000000      0xffffdd78      0x00007fff
0x7fffffffdc20: 0xf7a211f8      0x00007fff      0xf7fe2000      0x00007fff
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x00000000      0x00000000
0x7fffffffdc40: 0x00000001      0x00000000      0x0040062d      0x00000000
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x00000000
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff

(gdb) si
3: $rip = (void (*)()) 0x400505 <sum+4>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc50
// sp -> bp

(gdb) si
3: $rip = (void (*)()) 0x400509 <sum+8>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//根据内部变量及函数参数调整栈顶指针

(gdb) si 16
3: $rip = (void (*)()) 0x400551 <sum+80>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//存储实参值、内部变量赋值、为调用add函数进行参数传递准备

(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e      0x00000000      0x0040030b      0x00000000
0x7fffffffdc10: 0xffffffff      0x00000000      0x00000006      0x00000005
0x7fffffffdc20: 0x00000004      0x00000003      0x00000002      0x00000001
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x0000000a      0x00000014
0x7fffffffdc40: 0x0000001e      0x00000028      0x00000032      0x0000003c
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x00000000
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff
(gdb)info reg
rax            0xa      10
rbx            0x0      0
rcx            0x4      4
rdx            0x14     20
rsi            0x14     20
rdi            0xa      10
rbp            0x7fffffffdc50   0x7fffffffdc50
rsp            0x7fffffffdc18   0x7fffffffdc18
r8             0x5      5
r9             0x6      6
r10            0x7fffffffdb10   140737488345872
r11            0x7ffff7a32e50   140737348054608
r12            0x400400 4195328
r13            0x7fffffffdd60   140737488346464
r14            0x0      0
r15            0x0      0
rip            0x400551 0x400551 <sum+80>
eflags         0x216    [ PF AF IF ]
cs             0x33     51
ss             0x2b     43
ds             0x0      0
es             0x0      0
fs             0x0      0
gs             0x0      0

(gdb) si
add (m=0, n=-163754450) at test.c:3
3: $rip = (void (*)()) 0x4004ed <add>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc10
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e      0x00000000      0x0040030b      0x00000000
0x7fffffffdc10: 0x00400556      0x00000000      0x00000006      0x00000005
0x7fffffffdc20: 0x00000004      0x00000003      0x00000002      0x00000001
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x0000000a      0x00000014
0x7fffffffdc40: 0x0000001e      0x00000028      0x00000032      0x0000003c
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x00000000
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff
//系统自动完成返回地址压栈,为add函数调用作准备
(gdb) si
3: $rip = (void (*)()) 0x4004ee <add+1>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc08
//bp压栈
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0xf63d4e2e      0x00000000      0xffffdc50      0x00007fff
0x7fffffffdc10: 0x00400556      0x00000000      0x00000006      0x00000005
0x7fffffffdc20: 0x00000004      0x00000003      0x00000002      0x00000001
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x0000000a      0x00000014
0x7fffffffdc40: 0x0000001e      0x00000028      0x00000032      0x0000003c
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x00000000
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff

(gdb) si
3: $rip = (void (*)()) 0x4004f1 <add+4>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
// sp->bp
3: $rip = (void (*)()) 0x4004fd <add+16>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
//实参存储、参数到寄存器的转移
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014      0x0000000a      0xffffdc50      0x00007fff
0x7fffffffdc10: 0x00400556      0x00000000      0x00000006      0x00000005
0x7fffffffdc20: 0x00000004      0x00000003      0x00000002      0x00000001
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x0000000a      0x00000014
0x7fffffffdc40: 0x0000001e      0x00000028      0x00000032      0x0000003c
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x00000000
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff

rax            0x14     20
rbx            0x0      0
rcx            0x4      4
rdx            0xa      10
rsi            0x14     20
rdi            0xa      10
(gdb) si
3: $rip = (void (*)()) 0x4004ff <add+18>
2: $rbp = (void *) 0x7fffffffdc08
1: $rsp = (void *) 0x7fffffffdc08
rax            0x1e     30
//完成加运算
(gdb) si   
3: $rip = (void (*)()) 0x400500 <add+19>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc10
//恢复 bp 准备函数返回
(gdb) si
0x0000000000400556 in sum (a=1, b=2, c=3, d=4, e=5, f=6) at test.c:15
3: $rip = (void (*)()) 0x400556 <sum+85>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
//add函数返回
(gdb) si 20
3: $rip = (void (*)()) 0x400588 <sum+135>
2: $rbp = (void *) 0x7fffffffdc50
1: $rsp = (void *) 0x7fffffffdc18
// 完成sum函数中的其他工作
(gdb) si
3: $rip = (void (*)()) 0x400589 <sum+136>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc58
// leaveq 指令完成堆栈指针调整
(gdb) si
0x00000000004005cd in main () at test.c:25
3: $rip = (void (*)()) 0x4005cd <main+67>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//sum函数返回
(gdb) si
3: $rip = (void (*)()) 0x4005d0 <main+70>
2: $rbp = (void *) 0x7fffffffdc80
1: $rsp = (void *) 0x7fffffffdc60
//sum函数返回值通过eax寄存器传出并赋值给sum_of变量

(gdb) p &sum_of
$1 = (int *) 0x7fffffffdc7c
(gdb) p sum_of
$2 = 231
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014      0x0000000a      0xffffdc50      0x00007fff
0x7fffffffdc10: 0x00400556      0x00000000      0x00000006      0x00000005
0x7fffffffdc20: 0x00000004      0x00000003      0x00000002      0x00000001
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x0000000a      0x00000014
0x7fffffffdc40: 0x0000001e      0x00000028      0x00000032      0x0000003c
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x000000e7
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff

(gdb) si
3: $rip = (void (*)()) 0x4005d6 <main+76>
2: $rbp = (void *) 0x0
1: $rsp = (void *) 0x7fffffffdc88
//leaveq 函数调整堆栈指针
(gdb) si
__libc_start_main (main=0x40058a <main>, argc=1, argv=0x7fffffffdd68, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>,
    stack_end=0x7fffffffdd58) at libc-start.c:321
3: $rip = (void (*)()) 0x7ffff7a32f45 <__libc_start_main+245>
2: $rbp = (void *) 0x0
1: $rsp = (void *) 0x7fffffffdc90
(gdb) x /40xw 0x7fffffffdc00
0x7fffffffdc00: 0x00000014      0x0000000a      0xffffdc50      0x00007fff
0x7fffffffdc10: 0x00400556      0x00000000      0x00000006      0x00000005
0x7fffffffdc20: 0x00000004      0x00000003      0x00000002      0x00000001
0x7fffffffdc30: 0xf7ffe1c8      0x00007fff      0x0000000a      0x00000014
0x7fffffffdc40: 0x0000001e      0x00000028      0x00000032      0x0000003c
0x7fffffffdc50: 0xffffdc80      0x00007fff      0x004005cd      0x00000000
0x7fffffffdc60: 0x004005e0      0x00000000      0x00400400      0x00000001
0x7fffffffdc70: 0x00000002      0x00000003      0x00000004      0x000000e7
0x7fffffffdc80: 0x00000000      0x00000000      0xf7a32f45      0x00007fff
0x7fffffffdc90: 0x00000000      0x00000000      0xffffdd68      0x00007fff
 
堆栈内容分析
地址    内容    注释
0x7…dc00    0x00000014          实参n
0x7…dc04    0x0000000a          实参m
0x7…dc08    0xffffdc50          add函数后bp的原值存储此,此后pb、sp<-0x7fffffffdc08
0x7…dc0c    0x00007fff    
0x7…dc10    0x00400556         add函数调用之后的sp 位置,内容为add函数的返回地址
0x7…dc14    0x00000000          
0x7…dc18    0x00000006          实参 f  add调用前的sp指针 <sum+4>
0x7…dc1c    0x00000005    实参 e
0x7…dc20    0x00000004          实参 d
0x7…dc24    0x00000003          实参 c
0x7…dc28    0x00000002          实参 b
0x7…dc2c    0x00000001    实参 a
0x7…dc30    0xf7ffe1c8          
0x7…dc34    0x00007fff          
0x7…dc38    0x0000000a          sum内部变量a1
0x7…dc3c    0x00000014    sum内部变量a2
0x7…dc40    0x0000001e          sum内部变量a3
0x7…dc44    0x00000028          sum内部变量a4
0x7…dc48    0x00000032          sum内部变量a5
0x7…dc4c    0x0000003c    sum内部变量a6
0x7…dc50    0xffffdc80          sum函数后bp的原值存储在此,
此后bp<-0x7fffffffdc50 sp<-0x7fffffffdc18
0x7…dc54    0x00007fff          
0x7…dc58    0x004005cd          sum函数调用之后的sp位置,内容为sum函数的返回地址,系统自动压栈
0x7…dc5c    0x00000000    
0x7…dc60    0x004005e0          sum函数调用之前的sp位置,内容为main函数的返回地址,由<main+4>调整
0x7…dc64    0x00000000          
0x7…dc68    0x00400400          
0x7…dc6c    0x00000001    main函数内部变量x1
0x7…dc70    0x00000002          main函数内部变量x2
0x7…dc74    0x00000003          main函数内部变量x3
0x7…dc78    0x00000004          main函数内部变量x4
0x7…dc7c    0x000000e7    main函数内部变量sum_of
0x7…dc80    0x00000000          进入main函数后bp的原值存储在此
此后bp<-0x7fffffffdc80 sp<-0x7fffffffdc60
0x7…dc84    0x00000000    


 
 
// C函数调用堆栈结构分析例程
// 测试环境:平台ubuntu 14.04_3 64位
// GCC Ubuntu 4.8.5-2
  1 #include <stdio.h>                                                                                                                                  
  2 int add(int m, int n)
  3 {
  4     int x;
  5     x = 100;
  6     return x+m+n;
  7 }
  8 int sum(int a, int b, int c, int d, int e, int f)
  9 {
 10     int a1,a2,a3,a4,a5,a6;
 11     a1 = 10;
 12     a2 = 20;
 13     a3 = 30;
 14     a4 = 40;
 15     a5 = 50;
 16     a6 = 60;
 17  return add(a1,a2)+a3+a4+a5 \ +a6+a+b+c+d+e+f;
 18 }
 19
 20 int main()
 21 {
 22     int x1,x2,x3,x4,sum_of;
 23     x1 = 1;
 24     x2 = 2;
 25     x3 = 3;
 26     x4 = 4;
 27     sum_of = sum(x1,x2,x3,x4,5,6);
 28     return 0;
 29 }

64位Centos7上汇编运行32位程序 64位Centos7上汇编运行32位程序首先贴上源代码。 .ld-linux.so.2是动态加载器用来查找libc.so的 阅读详情

相关推荐

64位Linux下的栈溢出

0x01 x86和x86_64的区别 0x02 漏洞代码片段 0x03 触发溢出 0x04 控制RIP 0x05 跳入用户控制的缓冲区 0x06 执行shellcode 0x07 GDB vs 现实 0x08 结语

X86上汇编寻址方式总结

1 寄存器寻址 movl %eax, %edx edx = eax; 将寄存器eax赋值给edx 2 立即数寻址 movl $0x123, %edx edx = 0x123 将一个立即数放入寄存器 3 直接寻址 movl 0x123, %edx edx =*(int32_t*)0x123 将一个立即数所指的地址中的内容放到寄存器 4 间接寻址 movl (%ebx), %edx edx = *(int32_t*)ebx; 将一个寄存器内容(地址)所在的内容...

Nemo的博客 1381

广工计组实验f2一位全加器

一位全加器实验

weixin_63692154的博客 2847

一些基本的汇编指令

常见的寄存器 寄存器 16位 32位 64位 累加寄存器 AX EAX RAX 基址寄存器 BX EBX RBX 技术寄存器 CX ECX RCX 数据寄存器 DX EDX RDX 堆栈寄存器 BP EBP RBP 变址寄存器 SI ESI RSI 堆栈顶...

chunyuanmao2840的博客 747

[RK3588-Android12] 深入解析USB Type-C PD充电功能的DTS配置与内核驱动修改

本文深入探讨了在RK3588 Android12平台上禁用USB Type-C PD充电功能的实现方法。通过分析设备树(DTS)配置与内核驱动(TCPM框架)的联动修改,详细解读了如何通过添加`pd-disable`属性及修改`tcpm.c`驱动代码,使Type-C端口绕过PD协议协商,仅工作在传统电源模式,以满足工控等特定场景对供电稳定性和成本控制的需求。

9o8p7i6u5y的博客 994

模拟调制系统实战:从AM到FM的5种调制方式对比与选型指南

本文深度解析AM、DSB、SSB、VSB、FM五种经典模拟调制方式,从实现电路、频谱效率、抗噪性能及工程成本等维度进行实战对比。通过MATLAB/Simulink仿真案例,提供清晰的选型决策框架,帮助工程师在无人机图传、短波通信、广播系统等具体项目中,根据带宽、功耗和抗干扰需求选择最优方案。

study的专栏 932

NO.2汇编初步

汇编语言基础

Bubu的博客 551

ENSP实验一:防火墙基础配置

配置client(内网)、FTP Server(外网)的IP地址。进入防火墙,输入密码:默认为admin@123。

Carohuan的博客 1万+

解析C语言及对应的汇编指令--复杂数据类型

1. 数组 C代码: #include <stdio.h> #include <stdlib.h> int main() { //数组的初始化 int a[10] = {1,2,3,4,5}; //数组的访问 int b = a[2]; //数组的循环 for(int i=0;i<10;i++){ printf("%d\n",a[i]); } //数组的修改 a[0]=100; retu

小尘_OnMyWay的博客 1171

告别版本过低提示!微信3.9登录修复与聊天记录无缝迁移全攻略

本文详细解析了微信3.9版本过低提示的根源,并提供了完整的修复方案和聊天记录迁移指南。通过专用修复工具绕过版本检测,以及新旧版本聊天记录目录对比,帮助用户实现无缝迁移。特别提醒备份重要数据,确保操作安全。

weixin_42535461的博客 3157

生成mm grounding dino的onnx模型并在x-anylabeling中使用

X-AnyLabeling 是一款cvhub开发的交互式自动标注工具,其基于AnyLabeling进行构建和二次开发,在此基础上扩展并支持了许多的模型和功能,并借助Segment Anything和YOLO等主流模型提供强大的 AI 支持。其最新版基于grounding dino可以实现开放词汇检测及生成掩码。2024年,MMDet 3.3.0提出了 MM-Grounding-DINO。

blanokvaffy的博客 1729

linux命令mov,linux汇编指令之数据传输指令mov

作用将源操作数的值复制到目的操作数;这里规定源和目标操作不能都指向存储器位置,从一个存储器位置复制到另一个存储器位置需要两条指令,第一条指令将源操作数加载到寄存器,第二条将寄存器的值写到目标位置指令动作描述MOVS,DDMovb传送字节Movw传送字Movl传送双字MOVSS,DDMovsbw传送做了符号扩展字节到字Movsbl传送做了符号扩展字节到双字Movswl传送做了符号扩展字到双字MO...

weixin_39851887的博客 2070

广东省低应变题库

11.按《建筑地基基础检测规范》DBJ/T15-60-2019的规定,采用低应变法对混凝土预制桩进行检测时,地基基础设计等级为甲级的桩基工程抽检桩数不应少于总桩数的30%,其余桩基工程抽检桩数不应少于总桩数的20%,且不得少于10根;16.按《建筑地基基础检测规范》DBJ/T15-60-2019的规定,当对某桩的桩身完整性判定为III类时,可认为该桩不满足验收条件,不用进一步确定该桩桩身缺陷对桩身结构承载力的影响程度。2.地基基础检测所用计量器具均应在检定(校准、验证)的有效期内,性能符合相关技术要求。

ZShy001238的博客 319

linux环境下查看C/C++程序的堆栈信息

文章目录前言测试环境查看方法具体实践gdb调试core文件gdb附加到进程pstack输出堆栈信息strace打印程序运行情况总结 前言 经常在Windows上开发的工程师们可能已经习惯了图形化的调试界面,在源代码的编辑框上点击就可以添加断点,在调用堆栈的窗口就可以看到程序运行的堆栈信息,但是在 linux 环境下,面对命令行的天下,我们需要掌握一些命令,才能够查看C/C++程序的堆栈信息。 测...

AlbertS Home of Technology 9454

手把手教你学pcie--用Verilog搭建PCIe控制器核心模块

PCIe控制器是硬件设计的核心模块,负责实现设备与主机之间的高速通信。本文将以Verilog语言为例,分步骤讲解如何从零构建一个简化的PCIe控制器核心模块,涵盖事务层(TLP)生成、数据链路层(DLLP)处理和物理层(PHY)接口适配。目标是为嵌入式开发者、FPGA工程师提供一个可扩展的硬件设计框架。​。

MHD0815的博客 340

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

第12部分-Linux x86 64位汇编 函数C样式传递

第12部分-Linux x86 64位汇编 函数C样式传递 因为输入值和输出值可用的选择很多,这样哪个函数使用哪些寄存器和全局变量,或者哪些寄存器和全局变量传递哪些参数会是程序员的噩梦。 为此需要一个标准,使用某一标准一致地存放输入参数以便函数获取,一致地存放输出值便于主程序获取。 C把输入值传递给函数的解决方案是使用堆栈。C定义了返回主程序的值是用EAX,浮点用ST(0). C样式要求参数存放到堆栈中的顺序和函数的原型中的顺序相反。 .extern prin...

badman250的专栏 459

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

linux 函数栈溢出,64位Linux下的栈溢出

今天在看《捉虫日记》,其中讲解的Linux下的栈缓冲区溢出是32位机器的,和我的64位机器有些不同之处。下面是我在64位Linux (Ubuntu14) 下的栈缓冲区溢出实验的记录。首先是有溢出漏洞的程序,这个程序来自于《捉虫日记》。#includevoid overflow(char *arg){char buf[12];strcpy(buf, arg);}int main(int argc, ...

weixin_30175731的博客 696

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

linux 64位 shellcode,Linux 系统下提取 ShellCode

1.使用C语言编写一个获得系统Shell的小程序。#include int main(){char * shell[2];shell[0]="/bin/sh";shell[1]=NULL;execve(shell[0],shell,NULL);}编译并运行后,能够回弹Shell[root@localhost ~]# gcc -c lyshark.c[root@localhost ~]# gcc -...

weixin_36393674的博客 623

Linux系统上64位AT&T风格汇编语言计算乘方堆栈图分析(只有一层调用)

使用gdb调试分析堆栈图

qq_42108074的博客 340

如何在64位的linux系统上使用汇编和C语言混合编程

最近在看于渊的一个操作系统的实现,在第五章的时候汇编和C 同时使用时碰到了问题:代码如下 foo.s   bar.c 编译和链接的时候使用的指令:(AMD处理器,64位操作系统)   编译链接指令     汇编语言用nasm编写并用nasm编译器编译,而C语言用的是gcc编译,这些都没有问题,但是在链接的时候出错了,提示如下:   ld: i386 arch

qq_27816307的博客 567

Linux arm64异常简介和系统调用过程

Linux arm64异常简介和系统调用过程

小立仔 2112

Linux C/C++ 从内存转储中恢复64位ELF可执行文件

ELF(Executable and Linkable Format)是一种可执行文件和可链接文件的格式,它被广泛用于类Unix系统。ELF文件格式由以下几个部分组成: 1. ELF头(ELF Header):包含了文件的基本属性和结构信息,如文件类型、入口地址、程序头表位置等。 2. 程序头表(Program Header Table):包含了文件中各个段的信息,如代码段、数据段、堆栈段等。每个段都有一个对应的程序头,其中包含了该段在文件中的位置、大小、读写权限等信息。 3. 节头表(Section

chen1415886044的博客 2025

第47部分- Linux x86 64位汇编 C调用汇编

第47部分- Linux x86 64位汇编 C调用汇编 这个部分我们直接以例子来展示。 示例 定义casm.c文件如下: #include <string.h> int main() { char* str = "Hello World\n"; int len = strlen(str); printHelloWorld(str, len); return 0; } 调用printHelloWorld函数,我们知道在X86处理中调用函数的前6个参数位于寄存器rdi, r

badman250的专栏 1061

以time/gettimeofday系统调用为例分析ARM64 Linux 5.4.34

Linux源代码中的arch/x86/entry/syscalls/syscall_32.tbl和arch/x86/entry/syscalls/syscall_64.tbl 分别定义了32位x86和x86-64的系统调用内核处理函数,它们最终通过脚本转换按照系统调用号依次存入ia32_sys_call_table和sys_call_table数组中。do_int80_syscall_32和do_syscall_64的代码如arch/x86/entry/common.c。

qq_44803740的博客 343

Linux环境下的堆栈--调试C程序

完整的调试过程,跟踪堆栈变化,32位下。 注意64位和此不同。   a.c代码: #include int main() { AFunc(5,6); return 0; } int BFunc(int i,int j) { int m = 1; int n = 2; m = i; n = j; return m;

编程的本质是数学问题 2649

linux64 g 编译器,关于linux:在64位系统上组装32位二进制文件(GNU工具链)

我写了可以编译的汇编代码:as power.s -o power.o链接power.o目标文件时出现问题:ld power.o -o power为了在64位操作系统(Ubuntu 14.04)上运行,我在power.s文件的开头添加了.code32,但是仍然出现错误:分段故障(核心已转储)power.s:.code32.section .data.section .text.global _sta...

weixin_32821813的博客 514
下一篇: 树莓派 Linux + QT+ OpenCV 环境搭建
FuShaofeng
博客等级 码龄19年 140粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值