#include <stdio.h>
/*
* 从汇编层面看,C++类(class)的组织方式和结构体数据完全一致。
*/
class c
{
private:
int v1;
int v2;
public:
c() {
v1 = 667;
v2 = 999;
}
c(int a, int b)
{
v1 = a;
v2 = b;
}
void dump() {
printf("%d, %d\n", v1, v2);
}
};
int main()
{
class c c1;
class c c2(5, 6);
c1.dump();
c2.dump();
return 0;
}
#if 0
为什么这些函数有这些奇怪的名字?
其实这是编译器对函数名称进行改编(name mangling)的结果。
名称改编是一种在编译过程中,用ASCII字符串将函数、变量的名称重新改编的机制。
改编后的方法(类成员函数)名称就被用作该程序内部的函数名。这完全是因为编译器
Linker和加载DLL的OS装载器均不能识别C++或OOP(面向对象的变成语言)的数据结构。
构造函数本身就是一种函数,它们使用ECX存储结构体的指针,然后将指针复制到其自己
的局部变量里。当然,第二步不是必须的。
从C++的标准可知,构造函数的返回值是一个新建立的对象的指针,即this指针。
/*
* intel
*/
0000000000001169 <main>:
1169: f3 0f 1e fa endbr64
116d: 55 push %rbp // rsp=rsp-8, rsp=rbp ===> subq $8,%rsp, movq %rbp,(%rsp)
116e: 48 89 e5 mov %rsp,%rbp // rbp=rsp
1171: 48 83 ec 20 sub $0x20,%rsp // rsp = rsp-0x20
1175: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax // 把fs的偏移值x28放入rax
// 指向特定于线程或定义的结构
// %fs:0x28主要是用来起sentinel(哨兵)的作用,
117c: 00 00
117e: 48 89 45 f8 mov %rax,-0x8(%rbp) // 防止overflow的,即使用了8字节进行安全保护
1182: 31 c0 xor %eax,%eax // eax 清零
1184: 48 8d 45 e8 lea -0x18(%rbp),%rax // rax = rbp-0x18 = c1 = this
1188: 48 89 c7 mov %rax,%rdi // rdi = rax
118b: e8 4a 00 00 00 callq 11da <_ZN1cC1Ev> // _ZN1cC1Ev(rdi)
1190: 48 8d 45 f0 lea -0x10(%rbp),%rax // rax = rpb-0x10 = c2 = this
1194: ba 06 00 00 00 mov $0x6,%edx // edx = 6
1199: be 05 00 00 00 mov $0x5,%esi // esi = 5
119e: 48 89 c7 mov %rax,%rdi // rdi = rax
11a1: e8 58 00 00 00 callq 11fe <_ZN1cC1Eii> // _ZN1cC1Eii(rdi, esi, edx)
11a6: 48 8d 45 e8 lea -0x18(%rbp),%rax // rax = c1 = this
11aa: 48 89 c7 mov %rax,%rdi // rdi = rax
11ad: e8 74 00 00 00 callq 1226 <_ZN1c4dumpEv> // _ZN1c4dumpEv(rdi)
11b2: 48 8d 45 f0 lea -0x10(%rbp),%rax // rax = c2 = this
11b6: 48 89 c7 mov %rax,%rdi // rdi = rax
11b9: e8 68 00 00 00 callq 1226 <_ZN1c4dumpEv> // _ZN1c4dumpEv(rdi)
11be: b8 00 00 00 00 mov $0x0,%eax // eax = 0
11c3: 48 8b 4d f8 mov -0x8(%rbp),%rcx // 防止overflow
11c7: 64 48 33 0c 25 28 00 xor %fs:0x28,%rcx // fs:0x28 = 0
11ce: 00 00
11d0: 74 05 je 11d7 <main+0x6e> // 上面xor指令结果为零,执行正常退出,否则溢出检测失败报错
11d2: e8 89 fe ff ff callq 1060 <__stack_chk_fail@plt> // 溢出检测
11d7: c9 leaveq // ===> mov %rbp,%rsp, pop %rbp
11d8: c3 retq // ===> pop %rip
11d9: 90 nop
00000000000011da <_ZN1cC1Ev>:
11da: f3 0f 1e fa endbr64
11de: 55 push %rbp // rsp=rsp-8, rsp=rbp ===> subq $8,%rsp, movq %rbp,(%rsp)
11df: 48 89 e5 mov %rsp,%rbp // rbp=rsp
11e2: 48 89 7d f8 mov %rdi,-0x8(%rbp) // rbp-0x8 = rdi
11e6: 48 8b 45 f8 mov -0x8(%rbp),%rax // rax = rbp-0x8 = rdi
11ea: c7 00 9b 02 00 00 movl $0x29b,(%rax) // rax = 0x29b = 667
11f0: 48 8b 45 f8 mov -0x8(%rbp),%rax // rax = rbp-0x8 = rdi
11f4: c7 40 04 e7 03 00 00 movl $0x3e7,0x4(%rax) // rax+4 = 0x3e7 = 999
11fb: 90 nop
11fc: 5d pop %rbp // rbp=rsp, rsp+8 ===> movq %rsp,(%rbp), addq $8, (%rsp)
11fd: c3 retq // ===> pop %rip
00000000000011fe <_ZN1cC1Eii>:
11fe: f3 0f 1e fa endbr64
1202: 55 push %rbp // rsp=rsp-8, rsp=rbp ===> subq $8,%rsp, movq %rbp,(%rsp)
1203: 48 89 e5 mov %rsp,%rbp // rbp=rsp
1206: 48 89 7d f8 mov %rdi,-0x8(%rbp) // rbp-0x8 = rdi = this
120a: 89 75 f4 mov %esi,-0xc(%rbp) // rbp-0xc = esi = 5
120d: 89 55 f0 mov %edx,-0x10(%rbp) // rpb-0x10 = edx = 6
1210: 48 8b 45 f8 mov -0x8(%rbp),%rax // rax = this
1214: 8b 55 f4 mov -0xc(%rbp),%edx // edx = 5
1217: 89 10 mov %edx,(%rax) // rax = 5 ===> this.v1 = 5
1219: 48 8b 45 f8 mov -0x8(%rbp),%rax // rax = this
121d: 8b 55 f0 mov -0x10(%rbp),%edx // edx = 6
1220: 89 50 04 mov %edx,0x4(%rax) // rax+0x4 = 6 ===> this.v2 = 6
1223: 90 nop
1224: 5d pop %rbp // rbp=rsp, rsp+8 ===> movq %rsp,(%rbp), addq $8, (%rsp)
1225: c3 retq // ===> pop %rip
0000000000001226 <_ZN1c4dumpEv>:
1226: f3 0f 1e fa endbr64
122a: 55 push %rbp // rsp=rsp-8, rsp=rbp ===> subq $8,%rsp, movq %rbp,(%rsp)
122b: 48 89 e5 mov %rsp,%rbp // rbp=rsp
122e: 48 83 ec 10 sub $0x10,%rsp // rsp = rsp-0x10
1232: 48 89 7d f8 mov %rdi,-0x8(%rbp) // rbp-0x8 = rdi = this
1236: 48 8b 45 f8 mov -0x8(%rbp),%rax // rax = this.v1
123a: 8b 50 04 mov 0x4(%rax),%edx // edx = rax+0x4 = this.v2
123d: 48 8b 45 f8 mov -0x8(%rbp),%rax // rax = this.v1
1241: 8b 00 mov (%rax),%eax // eax = this.v1
1243: 89 c6 mov %eax,%esi // esi = this.v1
1245: 48 8d 3d b8 0d 00 00 lea 0xdb8(%rip),%rdi # 2004 <_IO_stdin_used+0x4> // rdi = "%d, %d\n"
124c: b8 00 00 00 00 mov $0x0,%eax // eax = 0
1251: e8 1a fe ff ff callq 1070 <printf@plt> // printf(rdi, esi, edx)
1256: 90 nop
1257: c9 leaveq // ===> mov %rbp,%rsp, pop %rbp
1258: c3 retq // ===> pop %rip
1259: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
/*
* arm
*/
int main()
{
104b0: b580 push {r7, lr}
104b2: b084 sub sp, #16 /* sp = sp - 16 */
104b4: af00 add r7, sp, #0 /* r7 = sp + 0 */
class c c1;
104b6: f107 0308 add.w r3, r7, #8 /* r3 = sp + 8, 存储对象c1的this指针 */
104ba: 4618 mov r0, r3 /* parameter 1 */
104bc: f000 f814 bl 104e8 <_ZN1cC1Ev> /* 调用构造函数 */
class c c2(5, 6);
104c0: 463b mov r3, r7 /* r3 = sp 存储对象c2的this指针 */
104c2: 2206 movs r2, #6 /* parameter 3 */
104c4: 2105 movs r1, #5 /* parameter 2 */
104c6: 4618 mov r0, r3 /* parameter 1 */
104c8: f000 f821 bl 1050e <_ZN1cC1Eii> /* 调用构造函数 */
c1.dump();
104cc: f107 0308 add.w r3, r7, #8 /* r3 = sp + 8 存储对象c1的this指针 */
104d0: 4618 mov r0, r3 /* r0 = this */
104d2: f000 f82f bl 10534 <_ZN1c4dumpEv> /* c1调用dump */
c2.dump();
104d6: 463b mov r3, r7 /* r3 = sp */
104d8: 4618 mov r0, r3 /* r0 = r3 */
104da: f000 f82b bl 10534 <_ZN1c4dumpEv> /* c2调用dump */
return 0;
104de: 2300 movs r3, #0 /* r3 = 0 */
}
104e0: 4618 mov r0, r3 /* r0 = 0 */
104e2: 3710 adds r7, #16 /* r7 += 16 */
104e4: 46bd mov sp, r7 /* sp = r7 */
104e6: bd80 pop {r7, pc}
000104e8 <_ZN1cC1Ev>:
c() {
104e8: b480 push {r7}
104ea: b083 sub sp, #12
104ec: af00 add r7, sp, #0
104ee: 6078 str r0, [r7, #4] /* 构造函数返回的this指针 */
v1 = 667;
104f0: 687b ldr r3, [r7, #4] /* r3 = r7+4 = this */
104f2: f240 229b movw r2, #667 ; 0x29b
104f6: 601a str r2, [r3, #0] /* r3+0 = this.v1 = 667 */
v2 = 999;
104f8: 687b ldr r3, [r7, #4] /* r3 = r7+4 = this */
104fa: f240 32e7 movw r2, #999 ; 0x3e7
104fe: 605a str r2, [r3, #4] /* r3+4 = this.v2 = 999 */
}
10500: 687b ldr r3, [r7, #4] /* r3 = r7+4 = this */
10502: 4618 mov r0, r3 /* 返回值 */
10504: 370c adds r7, #12
10506: 46bd mov sp, r7
10508: f85d 7b04 ldr.w r7, [sp], #4
1050c: 4770 bx lr
0001050e <_ZN1cC1Eii>:
c(int a, int b)
1050e: b480 push {r7}
10510: b085 sub sp, #20
10512: af00 add r7, sp, #0
10514: 60f8 str r0, [r7, #12] /* 构造函数返回的this指针 */
10516: 60b9 str r1, [r7, #8] /* 参数 1 */
10518: 607a str r2, [r7, #4] /* 参数 2 */
v1 = a;
1051a: 68fb ldr r3, [r7, #12]
1051c: 68ba ldr r2, [r7, #8] /* a */
1051e: 601a str r2, [r3, #0] /* r3+0 = v1 = a */
v2 = b;
10520: 68fb ldr r3, [r7, #12]
10522: 687a ldr r2, [r7, #4] /* b */
10524: 605a str r2, [r3, #4] /* r3+4 = v2 = b */
}
10526: 68fb ldr r3, [r7, #12]
10528: 4618 mov r0, r3 /* 返回值 */
1052a: 3714 adds r7, #20
1052c: 46bd mov sp, r7
1052e: f85d 7b04 ldr.w r7, [sp], #4
10532: 4770 bx lr
00010534 <_ZN1c4dumpEv>:
void dump() {
10534: b580 push {r7, lr}
10536: b082 sub sp, #8
10538: af00 add r7, sp, #0
1053a: 6078 str r0, [r7, #4] /* this 指针 */
printf("%d, %d\n", v1, v2);
1053c: 687b ldr r3, [r7, #4] /* r3 = this */
1053e: 6819 ldr r1, [r3, #0] /* r1 = [r3+0] = v1 */
10540: 687b ldr r3, [r7, #4] /* r3 = this */
10542: 685b ldr r3, [r3, #4] /* r3 = [r3+4] = v2 */
10544: 461a mov r2, r3 /* r2 = r3 = v2 */
10546: f240 50a8 movw r0, #1448 ; 0x5a8 /* r0 = 0x5a8 */
1054a: f2c0 0001 movt r0, #1 /* r0 = (1 << 16) | 0x05a8 = 0x105a8,此为数据段地址 */
1054e: f7ff ef38 blx 103c0 <printf@plt> /* printf(r0, r1, r2) */
}
10552: bf00 nop
10554: 3708 adds r7, #8
10556: 46bd mov sp, r7
10558: bd80 pop {r7, pc}
#endif