文章

undefined reference 问题查找

undefined reference 问题查找

问题

当编译器在链接报 undefined symbol 时,大部分情况下都会给出函数的调用链,但有些情况下不会给出相关信息,所以需要手动查找

假设有如下代码:

1
2
3
4
5
6
#include <variant>
int main()
{
    std::variant<int,double> v = 1.1;
    auto i = std::get<int>(v);
}

编译:

1
arm-none-eabi-g++ test.cpp -fno-exceptions

如果部分嵌入式 C++ 库没有实现 abort 函数的定义,则会报错:

1
2
3
4
5
$ arm-none-eabi-g++ test.cpp -fno-exceptions
d:/tools/arm gnu toolchain arm-none-eabi/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: d:/tools/arm gnu toolchain arm-none-eabi/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1\libc.a(libc_a-exit.o): in function `exit':
exit.c:(.text.exit+0x28): undefined reference to `_exit'
d:/tools/arm gnu toolchain arm-none-eabi/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: d:/tools/arm gnu toolchain arm-none-eabi/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1\libc.a(libc_a-abort.o): in function `abort':
abort.c:(.text.abort+0x10): undefined reference to `_exit'

解决过程

生成 .o 文件:

1
arm-none-eabi-g++ -g -c test.cpp

使用 nm 工具查找目录下引用了该函数的 .o 文件(假设是个大型项目,有很多文件):

1
find . -name '*.o' -exec sh -c 'nm -C {} | grep " U.* abort" >/dev/null && echo {}' \;

查找到其中的 ./test.o 使用了 abort:

1
2
$ find . -name '*.o' -exec sh -c 'nm -C {} | grep " U.* abort" >/dev/null && echo {}' \;
./test.o
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
$ nm -C test.o
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000000 t $a
00000044 t $d
00000000 r $d
00000068 t $d
00000000 W std::variant<int, double>::valueless_by_exception() const
00000000 W std::variant<int, double>::index() const
00000000 W std::__detail::__variant::_Variant_storage<true, int, double>::_M_valid() const
00000000 W std::__detail::__variant::_Uninitialized<int, true>::_M_get() &
00000000 W decltype(auto) std::__detail::__variant::__get<0u, std::variant<int, double>&>(std::variant<int, double>&)
00000000 W decltype(auto) std::__detail::__variant::__get_n<0u, std::__detail::__variant::_Variadic_union<int, double>&>(std::__detail::__variant::_Variadic_union<int, double>&)
00000000 W std::__throw_bad_variant_access(bool)
00000000 W std::__throw_bad_variant_access(char const*)
00000000 W int& std::get<int, int, double>(std::variant<int, double>&)
00000000 W std::variant_alternative<0u, std::variant<int, double> >::type& std::get<0u, int, double>(std::variant<int, double>&)
00000000 W std::__detail::__variant::_Variadic_union<int, double>& std::forward<std::__detail::__variant::_Variadic_union<int, double>&>(std::remove_reference<std::__detail::__variant::_Variadic_union<int, double>&>::type&)
00000000 W std::variant<int, double>& std::forward<std::variant<int, double>&>(std::remove_reference<std::variant<int, o 
uble>&>::type&)
         U abort
00000000 T main

使用 objdump 反汇编并查找引用路径:

1
arm-none-eabi-objdump -Cd test.o | c++filt | grep -A10 -B10 'abort'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
$ arm-none-eabi-objdump -Cd test.o | c++filt | grep -A10 -B10 'abort'
  68:   9999999a        .word   0x9999999a
  6c:   3ff19999        .word   0x3ff19999

Disassembly of section .text._ZSt26__throw_bad_variant_accessPKc:

00000000 <std::__throw_bad_variant_access(char const*)>:
   0:   e92d4800        push    {fp, lr}
   4:   e28db004        add     fp, sp, #4
   8:   e24dd008        sub     sp, sp, #8
   c:   e50b0008        str     r0, [fp, #-8]
  10:   ebfffffe        bl      0 <abort>

Disassembly of section .text._ZSt26__throw_bad_variant_accessb:

00000000 <std::__throw_bad_variant_access(bool)>:
   0:   e92d4800        push    {fp, lr}
   4:   e28db004        add     fp, sp, #4
   8:   e24dd008        sub     sp, sp, #8
   c:   e1a03000        mov     r3, r0
  10:   e54b3005        strb    r3, [fp, #-5]
  14:   e55b3005        ldrb    r3, [fp, #-5]

可以发现是 varient 库内部 abort。

附件

test.objdump:

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
223
224
225
226
227
228
229
230
231
232
233
test.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <main>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd018 	sub	sp, sp, #24
   c:	e24b301c 	sub	r3, fp, #28
  10:	e3a02000 	mov	r2, #0
  14:	e5832000 	str	r2, [r3]
  18:	e5832004 	str	r2, [r3, #4]
  1c:	e5832008 	str	r2, [r3, #8]
  20:	e583200c 	str	r2, [r3, #12]
  24:	e28f303c 	add	r3, pc, #60	; 0x3c
  28:	e893000c 	ldm	r3, {r2, r3}
  2c:	e50b201c 	str	r2, [fp, #-28]	; 0xffffffe4
  30:	e50b3018 	str	r3, [fp, #-24]	; 0xffffffe8
  34:	e3a03001 	mov	r3, #1
  38:	e54b3014 	strb	r3, [fp, #-20]	; 0xffffffec
  3c:	e24b301c 	sub	r3, fp, #28
  40:	e1a00003 	mov	r0, r3
  44:	ebfffffe 	bl	0 <main>
  48:	e1a03000 	mov	r3, r0
  4c:	e5933000 	ldr	r3, [r3]
  50:	e50b3008 	str	r3, [fp, #-8]
  54:	e3a03000 	mov	r3, #0
  58:	e1a00003 	mov	r0, r3
  5c:	e24bd004 	sub	sp, fp, #4
  60:	e8bd4800 	pop	{fp, lr}
  64:	e12fff1e 	bx	lr
  68:	9999999a 	.word	0x9999999a
  6c:	3ff19999 	.word	0x3ff19999

Disassembly of section .text._ZSt26__throw_bad_variant_accessPKc:

00000000 <std::__throw_bad_variant_access(char const*)>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd008 	sub	sp, sp, #8
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	ebfffffe 	bl	0 <abort>

Disassembly of section .text._ZSt26__throw_bad_variant_accessb:

00000000 <std::__throw_bad_variant_access(bool)>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd008 	sub	sp, sp, #8
   c:	e1a03000 	mov	r3, r0
  10:	e54b3005 	strb	r3, [fp, #-5]
  14:	e55b3005 	ldrb	r3, [fp, #-5]
  18:	e3530000 	cmp	r3, #0
  1c:	0a000002 	beq	2c <std::__throw_bad_variant_access(bool)+0x2c>
  20:	e59f001c 	ldr	r0, [pc, #28]	; 44 <std::__throw_bad_variant_access(bool)+0x44>
  24:	ebfffffe 	bl	0 <std::__throw_bad_variant_access(bool)>
  28:	ea000001 	b	34 <std::__throw_bad_variant_access(bool)+0x34>
  2c:	e59f0014 	ldr	r0, [pc, #20]	; 48 <std::__throw_bad_variant_access(bool)+0x48>
  30:	ebfffffe 	bl	0 <std::__throw_bad_variant_access(bool)>
  34:	e1a00000 	nop			; (mov r0, r0)
  38:	e24bd004 	sub	sp, fp, #4
  3c:	e8bd4800 	pop	{fp, lr}
  40:	e12fff1e 	bx	lr
  44:	00000000 	.word	0x00000000
  48:	00000020 	.word	0x00000020

Disassembly of section .text._ZSt3getIiJidEERT_RSt7variantIJDpT0_EE:

00000000 <int& std::get<int, int, double>(std::variant<int, double>&)>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd010 	sub	sp, sp, #16
   c:	e50b0010 	str	r0, [fp, #-16]
  10:	e3a03000 	mov	r3, #0
  14:	e50b3008 	str	r3, [fp, #-8]
  18:	e51b0010 	ldr	r0, [fp, #-16]
  1c:	ebfffffe 	bl	0 <int& std::get<int, int, double>(std::variant<int, double>&)>
  20:	e1a03000 	mov	r3, r0
  24:	e1a00003 	mov	r0, r3
  28:	e24bd004 	sub	sp, fp, #4
  2c:	e8bd4800 	pop	{fp, lr}
  30:	e12fff1e 	bx	lr

Disassembly of section .text._ZNSt8__detail9__variant7__get_nILj0ERNS0_15_Variadic_unionIJidEEEEEDcOT0_:

00000000 <decltype(auto) std::__detail::__variant::__get_n<0u, std::__detail::__variant::_Variadic_union<int, double>&>(std::__detail::__variant::_Variadic_union<int, double>&)>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd008 	sub	sp, sp, #8
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b0008 	ldr	r0, [fp, #-8]
  14:	ebfffffe 	bl	0 <decltype(auto) std::__detail::__variant::__get_n<0u, std::__detail::__variant::_Variadic_union<int, double>&>(std::__detail::__variant::_Variadic_union<int, double>&)>
  18:	e1a03000 	mov	r3, r0
  1c:	e1a00003 	mov	r0, r3
  20:	ebfffffe 	bl	0 <decltype(auto) std::__detail::__variant::__get_n<0u, std::__detail::__variant::_Variadic_union<int, double>&>(std::__detail::__variant::_Variadic_union<int, double>&)>
  24:	e1a03000 	mov	r3, r0
  28:	e1a00003 	mov	r0, r3
  2c:	e24bd004 	sub	sp, fp, #4
  30:	e8bd4800 	pop	{fp, lr}
  34:	e12fff1e 	bx	lr

Disassembly of section .text._ZNSt8__detail9__variant5__getILj0ERSt7variantIJidEEEEDcOT0_:

00000000 <decltype(auto) std::__detail::__variant::__get<0u, std::variant<int, double>&>(std::variant<int, double>&)>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd008 	sub	sp, sp, #8
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b0008 	ldr	r0, [fp, #-8]
  14:	ebfffffe 	bl	0 <decltype(auto) std::__detail::__variant::__get<0u, std::variant<int, double>&>(std::variant<int, double>&)>
  18:	e1a03000 	mov	r3, r0
  1c:	e1a00003 	mov	r0, r3
  20:	ebfffffe 	bl	0 <decltype(auto) std::__detail::__variant::__get<0u, std::variant<int, double>&>(std::variant<int, double>&)>
  24:	e1a03000 	mov	r3, r0
  28:	e1a00003 	mov	r0, r3
  2c:	e24bd004 	sub	sp, fp, #4
  30:	e8bd4800 	pop	{fp, lr}
  34:	e12fff1e 	bx	lr

Disassembly of section .text._ZSt3getILj0EJidEERNSt19variant_alternativeIXT_ESt7variantIJDpT0_EEE4typeERS4_:

00000000 <std::variant_alternative<0u, std::variant<int, double> >::type& std::get<0u, int, double>(std::variant<int, double>&)>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd008 	sub	sp, sp, #8
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b0008 	ldr	r0, [fp, #-8]
  14:	ebfffffe 	bl	0 <std::variant_alternative<0u, std::variant<int, double> >::type& std::get<0u, int, double>(std::variant<int, double>&)>
  18:	e1a03000 	mov	r3, r0
  1c:	e3530000 	cmp	r3, #0
  20:	13a03001 	movne	r3, #1
  24:	03a03000 	moveq	r3, #0
  28:	e20330ff 	and	r3, r3, #255	; 0xff
  2c:	e3530000 	cmp	r3, #0
  30:	0a000004 	beq	48 <std::variant_alternative<0u, std::variant<int, double> >::type& std::get<0u, int, double>(std::variant<int, double>&)+0x48>
  34:	e51b0008 	ldr	r0, [fp, #-8]
  38:	ebfffffe 	bl	0 <std::variant_alternative<0u, std::variant<int, double> >::type& std::get<0u, int, double>(std::variant<int, double>&)>
  3c:	e1a03000 	mov	r3, r0
  40:	e1a00003 	mov	r0, r3
  44:	ebfffffe 	bl	0 <std::variant_alternative<0u, std::variant<int, double> >::type& std::get<0u, int, double>(std::variant<int, double>&)>
  48:	e51b0008 	ldr	r0, [fp, #-8]
  4c:	ebfffffe 	bl	0 <std::variant_alternative<0u, std::variant<int, double> >::type& std::get<0u, int, double>(std::variant<int, double>&)>
  50:	e1a03000 	mov	r3, r0
  54:	e1a00003 	mov	r0, r3
  58:	e24bd004 	sub	sp, fp, #4
  5c:	e8bd4800 	pop	{fp, lr}
  60:	e12fff1e 	bx	lr

Disassembly of section .text._ZNKSt7variantIJidEE5indexEv:

00000000 <std::variant<int, double>::index() const>:
   0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   4:	e28db000 	add	fp, sp, #0
   8:	e24dd00c 	sub	sp, sp, #12
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b3008 	ldr	r3, [fp, #-8]
  14:	e5d33008 	ldrb	r3, [r3, #8]
  18:	e1a00003 	mov	r0, r3
  1c:	e28bd000 	add	sp, fp, #0
  20:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
  24:	e12fff1e 	bx	lr

Disassembly of section .text._ZNKSt7variantIJidEE22valueless_by_exceptionEv:

00000000 <std::variant<int, double>::valueless_by_exception() const>:
   0:	e92d4800 	push	{fp, lr}
   4:	e28db004 	add	fp, sp, #4
   8:	e24dd008 	sub	sp, sp, #8
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b3008 	ldr	r3, [fp, #-8]
  14:	e1a00003 	mov	r0, r3
  18:	ebfffffe 	bl	0 <std::variant<int, double>::valueless_by_exception() const>
  1c:	e1a03000 	mov	r3, r0
  20:	e2233001 	eor	r3, r3, #1
  24:	e20330ff 	and	r3, r3, #255	; 0xff
  28:	e1a00003 	mov	r0, r3
  2c:	e24bd004 	sub	sp, fp, #4
  30:	e8bd4800 	pop	{fp, lr}
  34:	e12fff1e 	bx	lr

Disassembly of section .text._ZSt7forwardIRSt7variantIJidEEEOT_RNSt16remove_referenceIS3_E4typeE:

00000000 <std::variant<int, double>& std::forward<std::variant<int, double>&>(std::remove_reference<std::variant<int, double>&>::type&)>:
   0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   4:	e28db000 	add	fp, sp, #0
   8:	e24dd00c 	sub	sp, sp, #12
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b3008 	ldr	r3, [fp, #-8]
  14:	e1a00003 	mov	r0, r3
  18:	e28bd000 	add	sp, fp, #0
  1c:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
  20:	e12fff1e 	bx	lr

Disassembly of section .text._ZSt7forwardIRNSt8__detail9__variant15_Variadic_unionIJidEEEEOT_RNSt16remove_referenceIS5_E4typeE:

00000000 <std::__detail::__variant::_Variadic_union<int, double>& std::forward<std::__detail::__variant::_Variadic_union<int, double>&>(std::remove_reference<std::__detail::__variant::_Variadic_union<int, double>&>::type&)>:
   0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   4:	e28db000 	add	fp, sp, #0
   8:	e24dd00c 	sub	sp, sp, #12
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b3008 	ldr	r3, [fp, #-8]
  14:	e1a00003 	mov	r0, r3
  18:	e28bd000 	add	sp, fp, #0
  1c:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
  20:	e12fff1e 	bx	lr

Disassembly of section .text._ZNRSt8__detail9__variant14_UninitializedIiLb1EE6_M_getEv:

00000000 <std::__detail::__variant::_Uninitialized<int, true>::_M_get() &>:
   0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   4:	e28db000 	add	fp, sp, #0
   8:	e24dd00c 	sub	sp, sp, #12
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e51b3008 	ldr	r3, [fp, #-8]
  14:	e1a00003 	mov	r0, r3
  18:	e28bd000 	add	sp, fp, #0
  1c:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
  20:	e12fff1e 	bx	lr

Disassembly of section .text._ZNKSt8__detail9__variant16_Variant_storageILb1EJidEE8_M_validEv:

00000000 <std::__detail::__variant::_Variant_storage<true, int, double>::_M_valid() const>:
   0:	e52db004 	push	{fp}		; (str fp, [sp, #-4]!)
   4:	e28db000 	add	fp, sp, #0
   8:	e24dd00c 	sub	sp, sp, #12
   c:	e50b0008 	str	r0, [fp, #-8]
  10:	e3a03001 	mov	r3, #1
  14:	e1a00003 	mov	r0, r3
  18:	e28bd000 	add	sp, fp, #0
  1c:	e49db004 	pop	{fp}		; (ldr fp, [sp], #4)
  20:	e12fff1e 	bx	lr
本文由作者按照 CC BY-SA 4.0 进行授权