17
17
import re
18
18
import fnmatch
19
19
from os .path import join , basename , splitext , dirname , exists
20
- from os import getenv
20
+ from os import getcwd , getenv
21
21
from distutils .spawn import find_executable
22
22
from distutils .version import LooseVersion
23
23
@@ -35,6 +35,7 @@ class GCC(mbedToolchain):
35
35
36
36
GCC_RANGE = (LooseVersion ("9.0.0" ), LooseVersion ("10.0.0" ))
37
37
GCC_VERSION_RE = re .compile (b"\d+\.\d+\.\d+" )
38
+ DWARF_PRODUCER_RE = re .compile (r'(DW_AT_producer)(.*:\s*)(?P<producer>.*)' )
38
39
39
40
def __init__ (self , target , notify = None , macros = None , build_profile = None ,
40
41
build_dir = None , coverage_patterns = None ):
@@ -149,12 +150,14 @@ def __init__(self, target, notify=None, macros=None, build_profile=None,
149
150
self .cppc += self .flags ['cxx' ] + self .flags ['common' ]
150
151
151
152
self .flags ['ld' ] += self .cpu
152
- self .ld = [join (tool_path , "arm-none-eabi-gcc" )] + self .flags ['ld' ]
153
+ self .ld = [join (tool_path , "arm-none-eabi-gcc" )]
154
+ self .ld += self .flags ['ld' ] + self .flags ['common' ]
153
155
self .sys_libs = ["stdc++" , "supc++" , "m" , "c" , "gcc" , "nosys" ]
154
156
self .preproc = [join (tool_path , "arm-none-eabi-cpp" ), "-E" , "-P" ]
155
157
156
158
self .ar = join (tool_path , "arm-none-eabi-ar" )
157
159
self .elf2bin = join (tool_path , "arm-none-eabi-objcopy" )
160
+ self .objdump = join (tool_path , "arm-none-eabi-objdump" )
158
161
159
162
self .use_distcc = (bool (getenv ("DISTCC_POTENTIAL_HOSTS" , False ))
160
163
and not getenv ("MBED_DISABLE_DISTCC" , False ))
@@ -305,12 +308,31 @@ def link(self, output, objects, libraries, lib_dirs, mem_map):
305
308
self .default_cmd (cmd )
306
309
mem_map = preproc_output
307
310
311
+ # NOTE: GCC_ARM_LTO_WORKAROUND
312
+ # This is a workaround for the GCC not using the strong symbols from
313
+ # C files to override the weak symbols from ASM files. This GCC bug is only
314
+ # present when building with the link-time optimizer (LTO) enabled. For
315
+ # more details please see:
316
+ # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83967
317
+ #
318
+ # This can be fixed by changing the order of object files in the linker
319
+ # command; objects providing the weak symbols and compiled from assembly
320
+ # must be listed before the objects providing the strong symbols.
321
+ # To keep things simple, ALL object files from ASM are listed before
322
+ # other object files.
323
+ asm_objects = []
324
+ if '-flto' in self .ld :
325
+ asm_objects = self .get_asm_objects (objects )
326
+ reorg_objects = (
327
+ [o for o in objects if o in asm_objects ] +
328
+ [o for o in objects if o not in asm_objects ]
329
+ )
308
330
# Build linker command
309
331
map_file = splitext (output )[0 ] + ".map"
310
332
cmd = (
311
333
(self .coverage_ld if self .coverage_patterns else self .ld ) +
312
334
["-o" , output , "-Wl,-Map=%s" % map_file ] +
313
- objects +
335
+ reorg_objects +
314
336
["-Wl,--start-group" ] +
315
337
libs +
316
338
["-Wl,--end-group" ]
@@ -382,6 +404,21 @@ def check_executable():
382
404
exec_name = join (TOOLCHAIN_PATHS ['GCC_ARM' ], 'arm-none-eabi-gcc' )
383
405
return exists (exec_name ) or exists (exec_name + '.exe' )
384
406
407
+ def check_if_obj_from_asm (self , obj_file ):
408
+ """Check if obj_file was build by the GNU Assembler."""
409
+ dw_producer = ''
410
+ cmd = [self .objdump , '--dwarf=info' , obj_file ]
411
+ stdout , stderr , rc = run_cmd (cmd , work_dir = getcwd (), chroot = self .CHROOT )
412
+ if rc != 0 :
413
+ return False
414
+ match = self .DWARF_PRODUCER_RE .search (stdout .encode ('utf-8' ))
415
+ if match :
416
+ dw_producer = match .group ('producer' )
417
+ return 'GNU AS' in dw_producer
418
+
419
+ def get_asm_objects (self , objects ):
420
+ """Return a list of object files built from ASM."""
421
+ return [o for o in objects if self .check_if_obj_from_asm (o )]
385
422
386
423
class GCC_ARM (GCC ):
387
424
pass
0 commit comments