(обратите внимание, что следующее относится только к MSVC)
Мой первый ответ вводил в заблуждение, так как я думал, что буквальное слияние было магией, выполненной компоновщиком (и поэтому флаг /GF
понадобился бы только компоновщику).
Однако это была ошибка. Оказывается, что компоновщик не имеет особого участия в слиянии строковых литералов - что происходит, когда компилятору задается опция /GF
, он помещает строковые литералы в раздел «COMDAT» объектного файла с именем объекта на основе на содержимое строкового литерала. Таким образом, флаг /GF
необходим для шага compile , а не для шага ссылки.
Когда вы используете опцию /GF
, компилятор помещает каждый строковый литерал в объектном файле в отдельный раздел как объект COMDAT. Различные объекты COMDAT с одинаковыми именами будут свернуты компоновщиком (я не совсем уверен в семантике COMDAT или в том, что может делать компоновщик, если объекты с одинаковыми именами имеют разные данные). Таким образом, файл C, который содержит
char* another_string = "this is a string";
Будет иметь что-то вроде следующего в объектном файле:
SECTION HEADER #3
.rdata name
0 physical address
0 virtual address
11 size of raw data
147 file pointer to raw data (00000147 to 00000157)
0 file pointer to relocation table
0 file pointer to line numbers
0 number of relocations
0 number of line numbers
40301040 flags
Initialized Data
COMDAT; sym= "`string'" (??_C@_0BB@LFDAHJNG@this?5is?5a?5string?$AA@)
4 byte align
Read Only
RAW DATA #3
00000000: 74 68 69 73 20 69 73 20 61 20 73 74 72 69 6E 67 this is a string
00000010: 00
с таблицей перемещений, соединяющей имя переменной another_string1
с литеральными данными.
Обратите внимание, что имя строкового литерального объекта явно основано на содержимом литеральной строки, но с некоторым искажением. Я сомневаюсь, что искажения описаны где-либо (но кто знает - может быть, кто-то обратный проектировал это).
В любом случае, если вы хотите, чтобы литералы в файле сборки обрабатывались одинаковым образом, вам необходимо организовать размещение литералов в объектном файле таким же образом. Честно говоря, я не знаю, какой (если вообще есть) механизм для этого может быть у ассемблера. Поместить объект в раздел «COMDAT», вероятно, довольно легко - получение имени объекта, основанного на содержимом строки (и искажение соответствующим образом), - это другая история.
Если не существует какой-либо директивы / ключевого слова сборки, которое конкретно поддерживает этот сценарий, я думаю, вам может не повезти Конечно, может быть один, но я достаточно ржавый с ml.exe
, чтобы не знать, и быстрый взгляд на скудные документы MSDN для ml.exe
ничего не выпрыгнул.
Однако, если вы хотите поместить строковые литералы в файл C и ссылаться на них в коде сборки через внешние ссылки, это должно сработать. Тем не менее, именно это и поддерживает Марк Рэнсом в своих комментариях к вопросу.