背景

写的代码在x64上单元测试一点问题没有,交叉编译出aarch64架构程序,跑在测试那里一开就崩,查了半天竟然是没有加return引发的血案…

调试过程

函数调用funca,调用完funca后本应该回到调用函数,但gdb查core却看到奇怪的堆栈信息funcb在funca之上,且崩在funcb里,这里简单写个小demo测试了一下(当然这个demo不会崩,因为没有访问成员变量)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>

using namespace std;

int funca()
{
cout << "this is func A" << endl;
//return 0;
}

int funcb()
{
cout << "this is func B" << endl;
return 0;
}

int main()
{
funca();
return 0;
}

编译指令为 (注意需要加上 -O2 优化才会复现现象)

1
/opt/aarch64-linux/bin/aarch64-linux-gnu-g++ -O2 main.cpp -o main

按道理来讲应该只会输出 “this is func A” 然后退出程序,结果程序在输出 “this is func A” 后,开始死循环输出 “this is func B”

根据openai的回答

在C++中,如果声明了返回值类型但没有显式地使用return语句,编译器通常会根据函数的返回类型自动插入一个隐式的return语句。对于非void类型的函数,如果没有显式地提供返回值,编译器通常会插入一个默认的return语句,例如return 0;,以确保函数能够正常返回一个值

然而,在ARM架构上,这种行为可能会有所不同。ARM架构下的编译器和链接器可能会有不同的处理方式,特别是在处理函数返回时。例如,某些编译器可能不会自动插入return语句,而是依赖于程序员显式地使用return语句来确保函数正确返回

也就是说没有加return的funca,执行完之后下一条指令不再是返回调用函数,而是指向了代码顺序里的下一条命令

汇编

使用

1
/opt/aarch64-linux/bin/aarch64-linux-gnu-g++ -O2 main.cpp -S

分别输出不加return和加return的汇编代码

  • 不加return
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
	.arch armv8-a+crc
.file "main.cpp"
.text
.section .text._ZNKSt5ctypeIcE8do_widenEc,"axG",@progbits,_ZNKSt5ctypeIcE8do_widenEc,comdat
.align 2
.p2align 4,,15
.weak _ZNKSt5ctypeIcE8do_widenEc
.type _ZNKSt5ctypeIcE8do_widenEc, %function
_ZNKSt5ctypeIcE8do_widenEc:
.LFB1296:
.cfi_startproc
mov w0, w1
ret
.cfi_endproc
.LFE1296:
.size _ZNKSt5ctypeIcE8do_widenEc, .-_ZNKSt5ctypeIcE8do_widenEc
.text
.align 2
.p2align 4,,15
.global _Z5funcav
.type _Z5funcav, %function
_Z5funcav:
.LFB1539:
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
adrp x1, .LC0
add x1, x1, :lo12:.LC0
mov x29, sp
mov x2, 14
str x19, [sp, 16]
.cfi_offset 19, -16
adrp x19, _ZSt4cout
add x19, x19, :lo12:_ZSt4cout
mov x0, x19
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
mov x0, x19
bl _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
.cfi_endproc
.LFE1539:
.size _Z5funcav, .-_Z5funcav
.align 2
.p2align 4,,15
.global _Z5funcbv
.type _Z5funcbv, %function
_Z5funcbv:
.LFB1540:
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
adrp x1, .LC1
mov x2, 14
mov x29, sp
stp x19, x20, [sp, 16]
.cfi_offset 19, -16
.cfi_offset 20, -8
adrp x19, _ZSt4cout
add x20, x19, :lo12:_ZSt4cout
mov x0, x20
add x1, x1, :lo12:.LC1
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr x0, [x19, #:lo12:_ZSt4cout]
ldr x0, [x0, -24]
add x0, x20, x0
ldr x19, [x0, 240]
cbz x19, .L11
ldrb w0, [x19, 56]
cbz w0, .L7
ldrb w1, [x19, 67]
.L8:
mov x0, x20
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov w0, 0
ldp x19, x20, [sp, 16]
ldp x29, x30, [sp], 32
.cfi_remember_state
.cfi_restore 30
.cfi_restore 29
.cfi_restore 19
.cfi_restore 20
.cfi_def_cfa_offset 0
ret
.p2align 2
.L7:
.cfi_restore_state
mov x0, x19
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr x2, [x19]
adrp x0, _ZNKSt5ctypeIcE8do_widenEc
add x0, x0, :lo12:_ZNKSt5ctypeIcE8do_widenEc
mov w1, 10
ldr x2, [x2, 48]
cmp x2, x0
beq .L8
mov x0, x19
blr x2
and w1, w0, 255
b .L8
.L11:
bl _ZSt16__throw_bad_castv
.cfi_endproc
.LFE1540:
.size _Z5funcbv, .-_Z5funcbv
.section .text.startup,"ax",@progbits
.align 2
.p2align 4,,15
.global main
.type main, %function
main:
.LFB1541:
.cfi_startproc
stp x29, x30, [sp, -16]!
.cfi_def_cfa_offset 16
.cfi_offset 29, -16
.cfi_offset 30, -8
mov x29, sp
bl _Z5funcav
.cfi_endproc
.LFE1541:
.size main, .-main
.align 2
.p2align 4,,15
.type _GLOBAL__sub_I__Z5funcav, %function
_GLOBAL__sub_I__Z5funcav:
.LFB2030:
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
mov x29, sp
str x19, [sp, 16]
.cfi_offset 19, -16
adrp x19, .LANCHOR0
add x19, x19, :lo12:.LANCHOR0
mov x0, x19
bl _ZNSt8ios_base4InitC1Ev
mov x1, x19
adrp x2, __dso_handle
ldr x19, [sp, 16]
adrp x0, _ZNSt8ios_base4InitD1Ev
ldp x29, x30, [sp], 32
.cfi_restore 30
.cfi_restore 29
.cfi_restore 19
.cfi_def_cfa_offset 0
add x2, x2, :lo12:__dso_handle
add x0, x0, :lo12:_ZNSt8ios_base4InitD1Ev
b __cxa_atexit
.cfi_endproc
.LFE2030:
.size _GLOBAL__sub_I__Z5funcav, .-_GLOBAL__sub_I__Z5funcav
.section .init_array,"aw",%init_array
.align 3
.xword _GLOBAL__sub_I__Z5funcav
.bss
.align 3
.set .LANCHOR0,. + 0
.type _ZStL8__ioinit, %object
.size _ZStL8__ioinit, 1
_ZStL8__ioinit:
.zero 1
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "this is func A"
.zero 1
.LC1:
.string "this is func B"
.hidden __dso_handle
.ident "GCC: (Kedacom VC 2019-12-09) 8.3.0"
.section .note.GNU-stack,"",@progbits
  • 加return
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
	.arch armv8-a+crc
.file "main.cpp"
.text
.section .text._ZNKSt5ctypeIcE8do_widenEc,"axG",@progbits,_ZNKSt5ctypeIcE8do_widenEc,comdat
.align 2
.p2align 4,,15
.weak _ZNKSt5ctypeIcE8do_widenEc
.type _ZNKSt5ctypeIcE8do_widenEc, %function
_ZNKSt5ctypeIcE8do_widenEc:
.LFB1296:
.cfi_startproc
mov w0, w1
ret
.cfi_endproc
.LFE1296:
.size _ZNKSt5ctypeIcE8do_widenEc, .-_ZNKSt5ctypeIcE8do_widenEc
.text
.align 2
.p2align 4,,15
.global _Z5funcav
.type _Z5funcav, %function
_Z5funcav:
.LFB1539:
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
adrp x1, .LC0
mov x2, 14
mov x29, sp
stp x19, x20, [sp, 16]
.cfi_offset 19, -16
.cfi_offset 20, -8
adrp x19, _ZSt4cout
add x20, x19, :lo12:_ZSt4cout
mov x0, x20
add x1, x1, :lo12:.LC0
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr x0, [x19, #:lo12:_ZSt4cout]
ldr x0, [x0, -24]
add x0, x20, x0
ldr x19, [x0, 240]
cbz x19, .L9
ldrb w0, [x19, 56]
cbz w0, .L5
ldrb w1, [x19, 67]
.L6:
mov x0, x20
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov w0, 0
ldp x19, x20, [sp, 16]
ldp x29, x30, [sp], 32
.cfi_remember_state
.cfi_restore 30
.cfi_restore 29
.cfi_restore 19
.cfi_restore 20
.cfi_def_cfa_offset 0
ret
.p2align 2
.L5:
.cfi_restore_state
mov x0, x19
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr x2, [x19]
adrp x0, _ZNKSt5ctypeIcE8do_widenEc
add x0, x0, :lo12:_ZNKSt5ctypeIcE8do_widenEc
mov w1, 10
ldr x2, [x2, 48]
cmp x2, x0
beq .L6
mov x0, x19
blr x2
and w1, w0, 255
b .L6
.L9:
bl _ZSt16__throw_bad_castv
.cfi_endproc
.LFE1539:
.size _Z5funcav, .-_Z5funcav
.align 2
.p2align 4,,15
.global _Z5funcbv
.type _Z5funcbv, %function
_Z5funcbv:
.LFB1540:
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
adrp x1, .LC1
mov x2, 14
mov x29, sp
stp x19, x20, [sp, 16]
.cfi_offset 19, -16
.cfi_offset 20, -8
adrp x19, _ZSt4cout
add x20, x19, :lo12:_ZSt4cout
mov x0, x20
add x1, x1, :lo12:.LC1
bl _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
ldr x0, [x19, #:lo12:_ZSt4cout]
ldr x0, [x0, -24]
add x0, x20, x0
ldr x19, [x0, 240]
cbz x19, .L16
ldrb w0, [x19, 56]
cbz w0, .L12
ldrb w1, [x19, 67]
.L13:
mov x0, x20
bl _ZNSo3putEc
bl _ZNSo5flushEv
mov w0, 0
ldp x19, x20, [sp, 16]
ldp x29, x30, [sp], 32
.cfi_remember_state
.cfi_restore 30
.cfi_restore 29
.cfi_restore 19
.cfi_restore 20
.cfi_def_cfa_offset 0
ret
.p2align 2
.L12:
.cfi_restore_state
mov x0, x19
bl _ZNKSt5ctypeIcE13_M_widen_initEv
ldr x2, [x19]
adrp x0, _ZNKSt5ctypeIcE8do_widenEc
add x0, x0, :lo12:_ZNKSt5ctypeIcE8do_widenEc
mov w1, 10
ldr x2, [x2, 48]
cmp x2, x0
beq .L13
mov x0, x19
blr x2
and w1, w0, 255
b .L13
.L16:
bl _ZSt16__throw_bad_castv
.cfi_endproc
.LFE1540:
.size _Z5funcbv, .-_Z5funcbv
.section .text.startup,"ax",@progbits
.align 2
.p2align 4,,15
.global main
.type main, %function
main:
.LFB1541:
.cfi_startproc
stp x29, x30, [sp, -16]!
.cfi_def_cfa_offset 16
.cfi_offset 29, -16
.cfi_offset 30, -8
mov x29, sp
bl _Z5funcav
mov w0, 0
ldp x29, x30, [sp], 16
.cfi_restore 30
.cfi_restore 29
.cfi_def_cfa_offset 0
ret
.cfi_endproc
.LFE1541:
.size main, .-main
.align 2
.p2align 4,,15
.type _GLOBAL__sub_I__Z5funcav, %function
_GLOBAL__sub_I__Z5funcav:
.LFB2030:
.cfi_startproc
stp x29, x30, [sp, -32]!
.cfi_def_cfa_offset 32
.cfi_offset 29, -32
.cfi_offset 30, -24
mov x29, sp
str x19, [sp, 16]
.cfi_offset 19, -16
adrp x19, .LANCHOR0
add x19, x19, :lo12:.LANCHOR0
mov x0, x19
bl _ZNSt8ios_base4InitC1Ev
mov x1, x19
adrp x2, __dso_handle
ldr x19, [sp, 16]
adrp x0, _ZNSt8ios_base4InitD1Ev
ldp x29, x30, [sp], 32
.cfi_restore 30
.cfi_restore 29
.cfi_restore 19
.cfi_def_cfa_offset 0
add x2, x2, :lo12:__dso_handle
add x0, x0, :lo12:_ZNSt8ios_base4InitD1Ev
b __cxa_atexit
.cfi_endproc
.LFE2030:
.size _GLOBAL__sub_I__Z5funcav, .-_GLOBAL__sub_I__Z5funcav
.section .init_array,"aw",%init_array
.align 3
.xword _GLOBAL__sub_I__Z5funcav
.bss
.align 3
.set .LANCHOR0,. + 0
.type _ZStL8__ioinit, %object
.size _ZStL8__ioinit, 1
_ZStL8__ioinit:
.zero 1
.section .rodata.str1.8,"aMS",@progbits,1
.align 3
.LC0:
.string "this is func A"
.zero 1
.LC1:
.string "this is func B"
.hidden __dso_handle
.ident "GCC: (Kedacom VC 2019-12-09) 8.3.0"
.section .note.GNU-stack,"",@progbits

确实是不一致的,当然目前我还看不懂aarch64的汇编,挖个坑,有空要学一下

总结

不要过度信任所有编译器都会处理好不加return的情况,还是要规范写代码呀!定义了返回类型就要加return。