0 参考资料
GNU-LD-v2.30-中文手册.pdf
GNU linker.pdf
1 前言
一个完整的编译工具链应该包含以下4个部分:
(1)编译器
(2)汇编器
(3)链接器
(4)lib库
在GNU工具链中,对应的是:
(1)编译器:GCC(GNU Compiler Collection,GNU编译器套件)
(2)汇编器:GAS(GNU Assembler,GNU汇编器)
(3)链接器:LD(GNU Linker,GNU链接器)
(4)lib库:glibc(GNU C Library,GNU C 库)
本文介绍GNU编译器(GCC)编译的4个过程及.elf、.list、.map文件功能。
2 GNU编译器(GCC):编译的4个过程及.elf、.list、.map文件功能说明
2.1 GCC编译的4个阶段
GCC编译按顺序分成4个阶段:预处理、编译、汇编、链接。详细操作见上图。
2.2 .elf、.list、.map文件功能说明
2.2 .elf文件
elf全称是Executable and Linkable Format(可执行链接格式),生成于汇编阶段(目标文件.o就是elf格式文件)。
一个elf文件主要由三部分组成:elf头(ELF Header)、程序头表(Program Header Table)、节区头表(Section Header Table)。elf头包含了有关elf文件的基本信息如文件类型、机器类型、段数量及位置等;程序头表描述了文件中各个段的信息;节区头表描述了文件中各个节区的信息。
在Windows下可以使用安装了AnyELF插件的Total Commander工具查看.elf文件,参考博客:Windows上浏览ELF文件。下图是使用该插件查看到的.elf文件实例:
2.2 .list文件
.list文件扩展名一般为.list或.lst,是纯文本文件。它由.elf文件反汇编(也就是将机器码转换为汇编)得来。里面包含了指令地址、指令机器码、指令机器码反汇编得到的汇编指令。如下所示:
通过.list文件我们可以很清晰看到源码和最终生成的汇编语句、机器码、指令地址,对调试阶段排查bug非常有用。
2.3 .map文件
.map文件扩展名一般是.map,是纯文本文件。它里面描述了程序的源代码和目标代码之间的映射关系,主要包括以下几个关键部分:
(1)模块、段(入口)交叉引用。描述了各个源文件之间函数调用关系,展示了哪些函数调用了其它函数,以及这些调用在内存中的位置
(2)删除镜像未使用的程序段。描述了哪些会被删除的程序段,便于开发者确认哪些代码被优化掉了
(3)内存分布。这也是.map最常用的功能,它描述了各个段(.text段、.data段、.bss段)在内存中的地址及大小
(4)映射组件大小。.map文件还会给出整个镜像代码占用的总空间信息
以下是一个.map文件实例:
2.3 如何生成.list、.map文件
生成方法参考stm32MP135工程的makefile文件:
Tool invocations
################################################################################
# Automatically-generated file. Do not edit!
# Toolchain: GNU Tools for STM32 (12.3.rel1)
################################################################################
-include ../makefile.init
RM := rm -rf
# All of the sources participating in the build are defined here
-include sources.mk
-include Core/Startup/subdir.mk
-include Core/Net/subdir.mk
-include Core/Drivers/STM32MP13xx_HAL_Driver/Src/subdir.mk
-include Core/Common/subdir.mk
-include Core/Bsp/subdir.mk
-include objects.mk
ifneq ($(MAKECMDGOALS),clean)
ifneq ($(strip $(S_DEPS)),)
-include $(S_DEPS)
endif
ifneq ($(strip $(S_UPPER_DEPS)),)
-include $(S_UPPER_DEPS)
endif
ifneq ($(strip $(C_DEPS)),)
-include $(C_DEPS)
endif
endif
-include ../makefile.defs
OPTIONAL_TOOL_DEPS := \
$(wildcard ../makefile.defs) \
$(wildcard ../makefile.init) \
$(wildcard ../makefile.targets) \
BUILD_ARTIFACT_NAME := stm32MP135
BUILD_ARTIFACT_EXTENSION := elf
BUILD_ARTIFACT_PREFIX :=
BUILD_ARTIFACT := $(BUILD_ARTIFACT_PREFIX)$(BUILD_ARTIFACT_NAME)$(if $(BUILD_ARTIFACT_EXTENSION),.$(BUILD_ARTIFACT_EXTENSION),)
# Add inputs and outputs from these tool invocations to the build variables
EXECUTABLES += \
stm32MP135.elf \
MAP_FILES += \
stm32MP135.map \
SIZE_OUTPUT += \
default.size.stdout \
OBJDUMP_LIST += \
stm32MP135.list \
# All Target
all:
+@$(MAKE) --no-print-directory main-build && $(MAKE) --no-print-directory post-build
# Main-build Target
main-build: stm32MP135.elf secondary-outputs
# Tool invocations
stm32MP135.elf stm32MP135.map: $(OBJS) $(USER_OBJS) D:\stm32MP135\Application\STM32MP135DAEX_RAM.ld makefile objects.list $(OPTIONAL_TOOL_DEPS)
arm-none-eabi-gcc -o "stm32MP135.elf" @"objects.list" $(USER_OBJS) $(LIBS) -mcpu=cortex-a7 -T"D:\stm32MP135\Application\STM32MP135DAEX_RAM.ld" --specs=nosys.specs -Wl,-Map="stm32MP135.map" -Wl,--gc-sections -static -mfpu=vfpv4-d16 -mfloat-abi=hard -mthumb -Wl,--start-group -lc -lm -Wl,--end-group
@echo 'Finished building target: $@'
@echo ' '
default.size.stdout: $(EXECUTABLES) makefile objects.list $(OPTIONAL_TOOL_DEPS)
arm-none-eabi-size $(EXECUTABLES)
@echo 'Finished building: $@'
@echo ' '
stm32MP135.list: $(EXECUTABLES) makefile objects.list $(OPTIONAL_TOOL_DEPS)
arm-none-eabi-objdump -h -S $(EXECUTABLES) > "stm32MP135.list"
@echo 'Finished building: $@'
@echo ' '
# Other Targets
clean:
-$(RM) stm32MP135.elf stm32MP135.list stm32MP135.map default.size.stdout
-@echo ' '
post-build:
"C:\STM32Cube\Repository\STM32Cube_FW_MP13_V1.1.0\Utilities\ImageHeader\postbuild_STM32MP13.sh" "D:\ST\STM32CubeIDE_1.15.0\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.gnu-tools-for-stm32.12.3.rel1.win32_1.0.100.202403111256\tools\bin" "stm32MP135"
-@echo ' '
secondary-outputs: $(SIZE_OUTPUT) $(OBJDUMP_LIST)
fail-specified-linker-script-missing:
@echo 'Error: Cannot find the specified linker script. Check the linker settings in the build configuration.'
@exit 2
warn-no-linker-script-specified:
@echo 'Warning: No linker script specified. Check the linker settings in the build configuration.'
.PHONY: all clean dependents main-build fail-specified-linker-script-missing warn-no-linker-script-specified post-build
-include ../makefile.targets