1717import re
1818import fnmatch
1919from os .path import join , basename , splitext , dirname , exists
20- from os import getenv
20+ from os import getcwd , getenv
2121from distutils .spawn import find_executable
2222from distutils .version import LooseVersion
2323
@@ -35,6 +35,7 @@ class GCC(mbedToolchain):
3535
3636 GCC_RANGE = (LooseVersion ("9.0.0" ), LooseVersion ("10.0.0" ))
3737 GCC_VERSION_RE = re .compile (b"\d+\.\d+\.\d+" )
38+ DWARF_PRODUCER_RE = re .compile (r'(DW_AT_producer)(.*:\s*)(?P<producer>.*)' )
3839
3940 def __init__ (self , target , notify = None , macros = None , build_profile = None ,
4041 build_dir = None , coverage_patterns = None ):
@@ -149,12 +150,14 @@ def __init__(self, target, notify=None, macros=None, build_profile=None,
149150 self .cppc += self .flags ['cxx' ] + self .flags ['common' ]
150151
151152 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' ]
153155 self .sys_libs = ["stdc++" , "supc++" , "m" , "c" , "gcc" , "nosys" ]
154156 self .preproc = [join (tool_path , "arm-none-eabi-cpp" ), "-E" , "-P" ]
155157
156158 self .ar = join (tool_path , "arm-none-eabi-ar" )
157159 self .elf2bin = join (tool_path , "arm-none-eabi-objcopy" )
160+ self .objdump = join (tool_path , "arm-none-eabi-objdump" )
158161
159162 self .use_distcc = (bool (getenv ("DISTCC_POTENTIAL_HOSTS" , False ))
160163 and not getenv ("MBED_DISABLE_DISTCC" , False ))
@@ -305,12 +308,31 @@ def link(self, output, objects, libraries, lib_dirs, mem_map):
305308 self .default_cmd (cmd )
306309 mem_map = preproc_output
307310
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+ )
308330 # Build linker command
309331 map_file = splitext (output )[0 ] + ".map"
310332 cmd = (
311333 (self .coverage_ld if self .coverage_patterns else self .ld ) +
312334 ["-o" , output , "-Wl,-Map=%s" % map_file ] +
313- objects +
335+ reorg_objects +
314336 ["-Wl,--start-group" ] +
315337 libs +
316338 ["-Wl,--end-group" ]
@@ -382,6 +404,21 @@ def check_executable():
382404 exec_name = join (TOOLCHAIN_PATHS ['GCC_ARM' ], 'arm-none-eabi-gcc' )
383405 return exists (exec_name ) or exists (exec_name + '.exe' )
384406
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 )]
385422
386423class GCC_ARM (GCC ):
387424 pass
0 commit comments