Как сослаться на начало пользовательского сегмента в проекте Visual Studio?

Я изо всех сил пытаюсь преобразовать C-программу, связанную с ld, из цепочки инструментов gnu, чтобы она скомпилировалась как проект visual-studio (2005). Программа помещает символы .data в разные сегменты и на этапе инициализации копирует данные между сегментами. Указатели на начало и конец сегментов определены в сценарии компоновщика ld.

Я понимаю, как размещать переменные в разных определяемых пользователем сегментах, но я не смог понять, как определить константы компоновщика, такие как _start_of_my_segment, или есть ли что-то похожее на скрипт компоновщика в Visual Studio.

Моя цель состоит в том, чтобы иметь возможность скомпилировать программу, желательно без модификаций исходного кода, который ссылается на определенные компоновщиком символы, но с моей собственной компоновкой данных в проекте Visual Studio.

Ниже приведен пример C-кода, который иллюстрирует то, что я хотел бы сделать, и (урезанная, возможно, синтаксически неправильная) версия make-script, используемая при компоновке с gcc/ld.

Любые подсказки будут очень признательны!

#pragma data_seg( "MY_DATA_FOO" )
#pragma data_seg( "MY_DATA_BAR" )
#pragma comment(linker, "/section:MY_DATA_BAR,R")

__declspec(allocate("MY_DATA_FOO")) int foo1;
__declspec(allocate("MY_DATA_FOO")) int foo2;

__declspec(allocate("MY_DATA_BAR")) int bar1 = 1;
__declspec(allocate("MY_DATA_BAR")) int bar2 = 2;

#pragma data_seg( )
void test() {
    foo1 = bar1;
    foo2 = bar2;

    // i would rather do this as 
    //extern unsigned int __start_of_MY_DATA_FOO;
    //extern unsigned int __start_of_MY_DATA_BAR;
    //extern unsigned int __size_of_MY_DATA_BAR;
    //memcpy(__start_of_MY_DATA_FOO, _start_of_MY_DATA_BAR, _size_of_MY_DATA_BAR);
}

Псевдоскрипт-ссылка (что было бы эквивалентно для Visual Studio

MEMORY
{
  foo:  org=0x1000, len=0x100
  bar:  org=0x2000, len=0x100
}

SECTIONS
{
    GROUP:
    {
        MY_DATA_FOO : {}
        __start_of_MY_DATA_FOO = ADDR(MY_DATA_FOO);
        __end_of_MY_DATA_FOO = .;
        __size_of_MY_DATA_FOO = SIZEOF(MY_DATA_FOO);
    } > foo

    GROUP:
    {
        MY_DATA_BAR : {}
        __start_of_MY_DATA_BAR = ADDR(MY_DATA_BAR);
        __end_of_MY_DATA_BAR = .;
        __size_of_MY_DATA_BAR = SIZEOF(MY_DATA_BAR);
    } > bar
}

person ara    schedule 07.07.2010    source источник
comment
Это действительно то, что не следует делать. Наверняка есть переносимые способы написать ту же программу. Похоже, кто-то думал, что они умно дурачились с внутренними компонентами низкоуровневой цепочки сборки вместо того, чтобы правильно использовать C... Это примерно на один шаг выше, если предположить, что вы можете получить доступ к локальным переменным из вызываемой функции в ее вызывающем объекте после ее возврата...   -  person R.. GitHub STOP HELPING ICE    schedule 07.07.2010
comment
@ R.: Есть редкие, но иногда веские причины использовать этот шаблон. Я использовал его для добавления проверок отладки. В релизных сборках мои объекты независимы и не знают друг о друге. Но для отладки они есть. Легальный способ C/C++ - это центральный регистр для отслеживания этого, созданный только для отладки, на самом деле требует гораздо больше обслуживания для более чем 200 вещей, чем этот подход (этот подход является автоматическим). С другой стороны, импортируемость — это другая стоимость, которую это приносит.   -  person VoidStar    schedule 28.07.2015


Ответы (2)


заполнение может быть удалено путем слияния сегментов

Например

#pragma data_seg(".foo_begin")
#pragma data_seg(".foo_data")
#pragma data_seg(".foo_end")

#pragma comment( linker, "/merge:.foo_begin=.foo" )
#pragma comment( linker, "/merge:.foo_data=.foo" )
#pragma comment( linker, "/merge:.foo_end=.foo" )

__declspec(allocate(".foo_begin")) int foo_begin_marker;
__declspec(allocate(".foo_end")) int foo_end_marker;

__declspec(allocate(".foo_data")) int foo_data;
person dnk    schedule 06.08.2011
comment
Спасибо! Тем не менее, я все еще получаю 0x100 байтов между переменными (а вы?). Без команды слияния заполнение составляет 0x1000 байт, а сегменты оказываются в неправильном порядке, поэтому команда слияния имеет некоторый эффект и кажется столь же полезной, как и другой подход (с использованием $ в именах разделов). - person ara; 15.08.2011

Создайте дополнительные сегменты (они располагаются в памяти по алфавиту):

#pragma data_seg("MY_DATA_FOO__a")
#pragma data_seg("MY_DATA_FOO__z")
#pragma data_seg("MY_DATA_FOO__m")

__declspec(allocate("MY_DATA_FOO__a")) int fooFirst;
__declspec(allocate("MY_DATA_FOO__z")) int fooLast;
__declspec(allocate("MY_DATA_FOO__m")) int foo1;
__declspec(allocate("MY_DATA_FOO__m")) int foo2;

Затем скопируйте все между &fooFirst и &fooLast.

person Sergey Podobry    schedule 07.07.2010
comment
Спасибо за предложение. Однако, когда я пытаюсь это сделать, адрес fooFirst НЕ меньше, чем fooLast, а &foo1 больше, чем &fooLast. Также кажется, что есть некоторые дополнения для выравнивания сегментов даже с блоками 0x1000. Это может регулироваться некоторыми настройками компилятора и компоновщика. Любые подсказки о том, какие настройки вы использовали? - person ara; 07.07.2010
comment
Еще раз спасибо! Я нашел пример трюка, который вы предлагаете, в документе #pragma init_seg (здесь msdn.microsoft.com/en-us/library/7977wcck.aspx). В нем говорится, что имена разделов должны состоять из 8 символов или меньше. Разделы с одинаковыми именами до $ объединяются в один раздел. Порядок их объединения определяется сортировкой символов после символа $. И когда я изменил имена разделов на MY_DATA_FOO$a и т. д., они оказались правильно отсортированы. Однако размер каждого раздела по-прежнему дополняется нулями примерно до 0x100 байт, что затрудняет определение правильного конца сегмента. - person ara; 07.07.2010
comment
Вот пример из исходников ATL: #pragma section(ATL$__a, чтение, совместное использование) #pragma section(ATL$__z, чтение, совместное использование) #pragma section(ATL$__m, чтение, совместное использование) Попробуйте раздел вместо data_seg. - person Sergey Podobry; 07.07.2010
comment
Да, они оба работают (если использовать «$» в имени раздела). Однако оба по-прежнему добавляют некоторые отступы, поэтому я до сих пор не могу понять, как построить символ __size_of_MY_DATA_BAR. - person ara; 07.07.2010
comment
Хм... У меня тоже есть расклад. И это довольно странно. - person Sergey Podobry; 09.07.2010