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. Это работает, так как компоновщик сначала ищет скрипты компоновщика и файлы, включенные скриптами компоновщика в текущую папку.

Что не

  • К сожалению, наши заинтересованные стороны считают, что вышеуказанный метод слишком рискован и сложен для понимания. Я хотел бы переопределить значение символа в командной строке компоновщика примерно так:

    1. 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

    2. 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

    3. 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 будут следующими:

  1. Уже правильно

  2. 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

  3. 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 выше), он работал. Но в итоге мне пришлось пропатчить скрипт компоновщика.

Это решение на самом деле не переопределяет символ, но предоставляет способ, которым символ может быть определен, так что он может быть переопределен.

Другие вопросы по тегам