GNU LD: как переопределить значение символа (адрес), определенный сценарием компоновщика, указанным с помощью -T
Мой сценарий использования выглядит следующим образом:
- Я использую типичный SDK, который поставляется с проектами на основе Makefile
- Я верю, что компоновщик пропатчен gcc. gcc - версия дает мне 4.3.4
- SDK определяет скрипт компоновщика (назовем его Linker.ld)
- Linker.ld включает LinkerMemMap.cfg, который определяет абсолютные адреса для различных разделов в связанном образе ELF
- SDK предоставляет шаблоны приложений на основе Makefiles (GNU Make 3.81) и делает сам
- В предоставляемом SDK шаблоне Makefile, когда вызывается gcc, Linker.ld предоставляется с параметром командной строки -T, как показано ниже:
gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -o$(OUTPUT).elf
Мое требование заключается в следующем:
- Я хотел бы использовать разделы, определенные в Linker.ld, и использовать карту памяти в соответствии с LinkerMemMap.cfg, однако настроить конкретный символ (давайте назовем его SYMBOL_RAM_START), определенный в LinkerMemMap.cfg.
Что работает:
- Я попытался в make-файле, перед тем как связать окончательный образ ELF, скопируйте LinkerMemMap.cfg (который входит в Linker.ld) в каталог сборки и исправьте его, чтобы переопределить SYMBOL_RAM_START. Это работает, так как компоновщик сначала ищет скрипты компоновщика и файлы, включенные скриптами компоновщика в текущую папку.
Что не
К сожалению, наши заинтересованные стороны считают, что вышеуказанный метод слишком рискован и сложен для понимания. Я хотел бы переопределить значение символа в командной строке компоновщика примерно так:
gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections,--defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -o$(OUTPUT).elf
gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -o$(OUTPUT).elf
gcc $(OBJS) -l$(Lib1) -l$(Lib2) --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -o$(OUTPUT).elf
Похоже, что ни один из них не влияет на связанное изображение, созданное компоновщиком.
- Может ли --defsym переопределить символы, определенные с помощью линкерскрипта, указанного с помощью -T?
- Может кто-нибудь из вас, посмотрите, что я здесь не так делаю?
1 ответ
Пока я ждал ответа, я решил проблему. Здесь есть несколько проблем с этой проблемой, и я подумал объяснить свои выводы кому-то, кто может совершить ту же ошибку.
Прежде всего, любые параметры, передаваемые компоновщику, должны быть указаны с -Xlinker или с -Wl. Следовательно, 2 и 3 не будут работать в вышеуказанном случае. Исправленные 2 и 3 будут следующими:
Уже правильно
gcc $(OBJS) -l$(Lib1) -l$(Lib2) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -Xlinker --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -o$(OUTPUT).elf
gcc $(OBJS) -l$(Lib1) -l$(Lib2) -Xlinker --defsym=SYMBOL_RAM_START=$(VALUE_TO_OVERRIDE) -nostdlib -lgcc -L$(library_path) -g -msmall-mode -mconst-switch-tables -mas-mode -mno-initc -Wl,--start-group,--end-group,-T,$(PATH_TO_Linker.ld),--gc-sections -o$(OUTPUT).elf
Теперь для вариантов 1 и 2 выше, --defsym следует за сценарием компоновщика, а SYMBOL_RAM_START уже был определен сценарием компоновщика. Это отменяет это. Но переопределенное значение не будет использоваться, поскольку разделы уже определены, поскольку скрипт компоновщика уже использовался.
Для варианта 3, описанного выше, SYMBOL_RAM_START был определен до того, как компоновщик прочитал скрипт компоновщика. Следовательно, когда скрипт компоновщика анализируется, значение, указанное в скрипте, переопределяет его.
Решение:
Чтобы это работало, скрипт компоновщика должен будет условно инициализировать символ SYMBOL_RAM_START, как показано ниже:
SYMBOL_RAM_START = DEFINED ( SYMBOL_RAM_START )? SYMBOL_RAM_START : DEFAULT_VALUE;
Учитывая вышеизложенное в сценарии компоновщика, когда SYMBOL_RAM_START был определен до включения сценария компоновщика (как показано в варианте 3 выше), он работал. Но в итоге мне пришлось пропатчить скрипт компоновщика.
Это решение на самом деле не переопределяет символ, но предоставляет способ, которым символ может быть определен, так что он может быть переопределен.