Страницы

Поиск по вопросам

Показаны сообщения с ярлыком компоновщик. Показать все сообщения
Показаны сообщения с ярлыком компоновщик. Показать все сообщения

пятница, 14 февраля 2020 г.

Как отключить предупреждение “multiple definition of symbol”

#cpp #c #g++ #компоновщик #ld


Изучаю работу редактора связей и специально для этого написал программу, в которой
два раза появляется один и тот же символ. Хочу посмотреть на поведение. Однако, редактор
связей выдает предупреждение: 


  multiple definition of symbol


и отказывается дальше работать. Собираю через g++, есть подозрения, что это g++ выставляет
какой-то флаг для ld, чтобы редактор связей останавливал работу в таких случаях. Насколько
я знаю,такие ситуации допускаются, и  есть определенные правила для их разрешения.
Как заставить ld игнорировать множественное определение символа?
    


Ответы

Ответ 1



Насчет "такие ситуации допускаются и есть определенные правила": ситуации с множественными определениями одной и той же внешней сущности являются ошибками и в С++, и в С, хотя исторически многие реализации С в качестве расширения разрешают множественные внешние определения одной и то же переменной без инициализатора (формально это запрещено в С). Вот и все правила. А если вы хотите подавить ошибки для конкретного символа на уровне исходного кода - то просто объявите его weak, т.е. с __attribute__((weak)) А также можно отключить ошибку глобально, на уровне командной строки ld через опцию -z muldefs или ее синоним --allow-multiple-definition (т.е. если вы используете gcc для неявного вызова линкера, то -Wl,-z,muldefs или -Wl,--allow-multiple-definition). http://coliru.stacked-crooked.com/a/9e49a6024baf2589

Ответ 2



Всё, что написано далее, относится только к реализации системы компиляции GNU. Вы имеете 2 strong символа. То, что глобальная функция является strong символом, это очевидно. Доказательство того, что глобальная переменная без инициализатора (только в случае g++ при компиляции *.cpp-файлов) является strong символом, а не common или weak символом: Допустим, имеем 2 файла: f1.cpp и f2.cpp. В файле f1.cpp определена функция с сигнатурой int some(void), которая mangled (коверкается компилятором) в _Z4somev. В файле f2.cpp определена глобальная непроинициализированная переменная _Z4somev следующим образом: int _Z4somev;, то есть явно мы ей не присвоили никакое значение. Получаем relocatable object files (f1.o, f2.o): g++ -c f1.cpp; g++ -c f2.cpp. Команда readelf -s f2.o выдаст для символа глобальной переменной _Z4somev: а) В колонке Ndx не 'COM', то есть символ не является common; б) В колонке Bind не 'WEAK', то есть символ не является weak. Команда nm f2.o выдаст для символа глобальной переменной _Z4somev следующее: 0000000000000000 B _Z4somev. Важно то, что во второй колонке 'B'. Если бы символ был weak, то во второй колонке было бы 'V'. Если бы символ был common, то во второй колонке было бы 'C'. Если бы мы проделали те же самые действия, но в файле f2.cpp определили бы переменную _Z4somev следующим образом: int _Z4somev __attribute__((weak));, то в колонке Bind утилита readelf показала бы значение 'WEAK' для этого символа, а утилита nm показала бы значение 'V' для этого символа, то есть символ переменной _Z4somev является weak. Если переименовать файлы f1.cpp и f2.cpp в f1.c и f2.c соответственно, а название переменной изменить из _Z4somev в some (так как название функции some не будет mangled при вызове gcc), то если выполнить gcc -c f1.c; gcc -c f2.c; readelf -s f2.o; nm f2.o, то для символа глобальной переменной в колонке Ndx утилита readelf отобразит значение COM, что значит, что символ является common, а в колонке Bind - значение GLOBAL, что значит, что символ не является weak; а утилита nm во второй колонке отобразит C, что значит, что символ является common и не является weak. Если в коде для глобальной не extern переменной программист не добавил инициализатор, то символ этой переменной: При компиляции *.c-файлов с помощью gcc: а) Становится common; б) Не становится weak; в) Не становится strong. При компиляции *.cpp-файлов с помощью g++: а) Становится strong; б) Не становится weak; в) Не становится common. Шаги при компиляции, относящиеся к вопросу: Шаг 1. При компиляции с помощью g++ *.cpp, если компилятор встречает глобальную переменную без явной инициализации программистом (пример, int some;), то компилятор неявно пишет инициализатор, в котором переменной присваивается значение по умолчанию (например, int some = 0;). При компиляции с помощью gcc *.c, компилятор не будет в этих случаях неявно добавлять инициализатор. Понятно, что даже даже если ни программист, ни компилятор не добавили инициализатор, глобальная переменная всё равно проинициализируется значением 0, так как секция .bss заполняется нулями загрузчиком исполняемых файлов. Но синтаксическое наличие инициализатора, не важно кем добавленного, программистом или компилятором, влияет на шаг №2. Шаг 2. Этот шаг не отличается от того, каким образом была вызвана компиляция: gcc *.c или же g++ *.cpp. а) Если атрибут __attribute__((weak)) при объявлении переменной имеется, то символ является weak (и не является strong и не является common); б) Если атрибута __attribute__((weak)) нет, то: б.1) Если инициализатор есть (не важно, добавленный программистом или же компилятором), то глобальная переменная является strong (но не является weak и не является common); б.2) Если инициализатора нет, то глобальная переменная является common (но не является weak и не является strong). Компилятор (cc1, запускаемый при gcc -c *.c; cc1plus, запускаемый при g++ -c *.cpp) определяет то, каким будет символ: strong, weak или common и эту информацию далее передаёт программе as, которая создаёт файлы *.o и записывает в них информацию о типе символов, которую мы можем просмотреть с помощью утилит readelf и nm. Линкер (ld; вызывается программой collect2, которая в свою очередь вызывается программой gcc/g++, что видно с ключом -v) определяет то, какой именно символ, weak, strong или common, появляется в файлах *.o, основываясь на информации из таблицы символов, хранящихся в этих файлах (секция .symtab), которую мы просматривали с помощью утилит readelf и nm. Далее линкер ld использует следующие правила (при разрешении символьных ссылок), основываясь на полученной информации: Множество strong символов с одинаковым именем запрещены, поэтому линковщик выдаст ошибку. Если имеется 1 strong символ и несколько weak/common символов с одним именем, то линковщик выбирает strong символ. Если имеется несколько weak/common символов с одним именем, то линкер выбирает любой из них (чтобы предотвратить такое поведение, необходимо в gcc/g++ передать флаг -fno-common или использовать опцию -Werror). Ввиду того, что вопрос касался проблемы несогласованности полученного теоретического материала с практическими тестами этого материала, данный ответ позволяет аннигилировать эту несогласованность. Это плохо, когда имеется множество глобальных символов с одним и тем же именем.

пятница, 31 января 2020 г.

Подробности работы компилятора и линкера [дубликат]

#cpp #компоновщик


        
             
                
                    
                        
                            На этот вопрос уже даны ответы здесь:
                            
                        
                    
                
                        
                            В каком случае нужно определять функцию в заголовочном
файле?
                                
                                    (5 ответов)
                                
                        
                        
                            Что такое “Правило одного определения” (One definition
rule)?
                                
                                    (1 ответ)
                                
                        
                                Закрыт 2 года назад.
            
                    
Рассмотрим следующий пример:

// file header1.h
#include 

void foo()
{
    std::cout << "Foo" << '\n';
}

//  file source1.cpp
#include "header1.h"


//  file main.cpp
#include "header1.h"

int main()
{
    return 0;
}


В связи с тем, что определение foo находится в хедере (что не очень хорошо), который
включён в более чем один .cpp файл, линкер честно выдает ошибку наподобие:


multiple definition of foo ... first defined in main.o ...



Одно из решений - сделать foo статической функцией, что обеспечит одно определение
в объектных файлах:

static foo() { ... }


второе: 

inline foo() { ... }


третье: 

static inline foo() { ... }


Вопросы:


Почему inline функция тоже решает эту проблему?
Какие принципиальные отличия у этих решений? 

    


Ответы

Ответ 1



inline решает эту проблему потому, что спецификация языка этого требует. Правило Одного Определения (One Definition Rule) для inline функций ясно говорит, что inline функция с внешним связыванием может определяться в программе много раз в разных единицах трансляции (точнее: должна определяться везде, где одна используется и везде - одинаково). А уж как компиляторы/линкеры реализуют это требование - это их проблемы. Фактически, если такая функция породила тело в нескольких объектных файлах (т.е. не все ее вызовы заинлайнились), то линкеру будет предписано не ругаться на тему "multiple definition", а молча выбрать одно-единственное тело и остальные выбросить. Так как "классический" формат объектного файла не позволяет определить, где начинается и где заканчивается тело конкретной функции, для целей возможного будущего удаления компилятор их обычно помещает в выделенные секции объектного файла. Принципиальное отличие между inline и static вариантом заключается в том, что inline функция сохраняет внешнее связывание (external linkage) и ведет себя во всех отношениях как функция со внешним связыванием. Например, если разные единицы трансляции попробуют взять адрес inline функции, то везде обязательно должно получиться одно и то же значение. Статические переменные, определенные внутри такой inline функции тоже существуют в единственном экземпляре во всей программе, как и в любой другой функции со внешним связыванием. В static варианте наоборот, функция получает внутреннее связывание (internal linkage) - каждая единица трансляции получает свою копию функции со своим уникальным адресом. Принципиальных отличий между static inline и static нет, с той только разницей, что в первом случае дается подсказка компилятору.

Ответ 2



это очевидно из самой сути inline -- если код такой функции в самом деле "заинлайнен", то на него существует (логически) только одна ссылка (а именно в том месте, где код "инлайнится"), следовательно никаких проблем с "multiple definition" (т.е. проблемы выбора той или иной точки входа) не существует. тут принципиальное отличие возникает при наличии static переменных у таких (inline и static inline функций. В каждой единице компиляции у static inline будут свои экземпляры таких переменных (а у "не static" один экземпляр static переменной на весь загрузочный модуль (результат линковки)).

пятница, 10 января 2020 г.

DLang: Как правильно прилинковать GUI-библиотеку DWT?

#gui #компоновщик #d


В процессе ознакомления с D, появилось желание написать что-нибудь простенькое с
GUI. В качестве GUI-библиотеки выбрал DWT, т.к. кроссплатформенно и является биндингом
с SWT (много обучающего материала по последнему).

Проект был скачан с ГитХаба, собран и перенесен в папку C:\D\. Методом проб и ошибок
была получена работающая команда для сборки демонстрационного окошка с надписью "Hello,
DWT!" посередине:

dmd.exe "..\src\%1" -IC:\\D\\dwt\\imp ^
-JC:\\D\\dwt\\org.eclipse.swt.win32.win32.x86\\res ^
-L+C:\\D\\dwt\\lib\\ -L+org.eclipse.swt.win32.win32.x86.lib ^
-L+dwt-base.lib -L/SUBSYSTEM:windows:4 ^
-L/rc:..\res\resource.res


, что соответствует следующим параметрам в dub.json:

"importPaths": ["C:\\D\\dwt\\imp"],
"stringImportPaths": ["C:\\D\\dwt\\org.eclipse.swt.win32.win32.x86\\res"],
"lflags": ["+C:\\D\\dwt\\lib\\"
   , "+org.eclipse.swt.win32.win32.x86.lib"
   , "+dwt-base.lib", "/SUBSYSTEM:windows:4"
   , "/rc:res\\resource.res"]


Код самой программы: 

import org.eclipse.swt.all;
void main()
{
    auto display = new Display;
    auto shell = new Shell(display);
    shell.setLayout(new GridLayout(4, false));
    auto label = new Label(shell, 0);
    label.setText("Hello, DWT!");
    shell.pack();
    shell.open();
    while (!shell.isDisposed)
        if (!display.readAndDispatch())
            display.sleep();
    display.dispose();
}


И программа собирается в один в один единственный exe без зависимостей и на ура запускается
на ОС от WinXP до Windows8. Но меня терзают серьезные сомнения, что я тут наворотил
лишнего, и можно было бы как-то по-проще. 

Если кто-то разумеет в dmd или dub и в тонкостях их отношений с линковщиком, подскажите,
как в описанной ситуации поступил бы белый человек.
    


Ответы

Ответ 1



Проще будет, если библиотеку добавят в dub-репозиторий. Пока этого не случится, нужно прописывать пути самостоятельно. Шаги, которые нужно сделать. Выбираете место для библиотеки (на вашем примере, это может быть C:\D) Открываете консоль, заходите в выбранную директорию. Следуете инструкции с github: Клонируете репозиторий git clone --recursive git://github.com/d-widget-toolkit/dwt.git Появится папка C:\D\dwt с проектом и зависимостями. Заходите в эту папку cd dwt Выполняете сборку проекта rdmd build base swt. Собственно, теперь можно подключать библиотеку в свой проект. Для компиляции из командной строки нужно будет выполнить dmd main.d -IC:\D\dwt\imp -JC:\D\dwt\res -L+C:\D\dwt\lib\ "-L+org.eclipse.swt.win32.win32.x86.lib" "-L+dwt-base.lib" -L/SUBSYSTEM:WINDOWS:4.0` Именно это и написано в инструкции на гитхабе: dmd main.d -I\imp -J\res -L+\lib\ ^ "-L+org.eclipse.swt.win32.win32.x86.lib" "-L+dwt-base.lib" ^ -L/SUBSYSTEM:WINDOWS:4.0 - это путь к директории самого dwt, лезть к res в org.eclipse.swt.win32.win32.x86 не требуется, так как нужный res лежит в самой dwt. Итог у вас почти правильный. Если внимательно следовать инструкции к библиотеке, то ошибок никаких нет. Для того, чтобы в будущем не прописывать все пути/зависимости в проекте, можно сделать "пустой" проект и впоследствии просто копировать его в качестве нового. P.S. Лично я использую библиотеку DlangUI. Кроссплатформенная, с широкими возможностями, интерфейсы можно удобно собирать, используя разметку DML (похожую на QML) и др. Есть статья от автора. P.P.S. Обязательно используйте фигурные скобки во while while (!shell.isDisposed) { if (!display.readAndDispatch()) display.sleep(); } Иначе, добавив ещё какую-нибудь строку кода, можно получить некорректную логику программы.

понедельник, 6 января 2020 г.

Для чего нужен флаг -s в gcc?

#cpp #c #компоновщик


Собственно ответ на вопрос я нашел:


  Remove all symbol table and relocation information from the
  executable. (https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options)


Нашел статью о relocation information:


  relocation information 
  
  настроечная информация (информация для
  компоновщика о том, какие конструкции в объектном файле должны быть
  заменены адресами объектов, определенных в других исходных файлах)
  
  (http://computer_en_ru.academic.ru/36046/relocation_information)


Затем нашел ответ на вопрос, что за symbol table такая:
https://stackoverflow.com/questions/69112/what-is-a-symbol-table

Но с моим знанием английского целостный взгляд на проблему так и не сложился. Может
кто-то поможет собрать все части пазла в единую картину?
    


Ответы

Ответ 1



Компилятор помещает в исполняемый файл не только то, что нужно для запуска (то есть код и данные), но ещё и дополнительную (и в общем-то ненужную) информацию (к примеру, имена всех переменных и функций, включая те, что были объявлены со спецификатором static). Эта дополнительная информация нужна только на стадии компоновки, но компилятор оставляет её и в конечном исполняемом файле, возможно для удобства дальнейшей отладки. За её вырезание и отвечает флаг -s. Возьмём, к примеру, программу, состоящую из двух файлов исходных кодов: main.cpp #include #include std::string partOne("Hello, "); // Глобальная переменная std::string getString(); // Прототип функции, объявленной в другом файле int main() { std::cout << getString() << std::endl; return 0; } other.cpp #include extern std::string partOne; static std::string partTwo("World!"); std::string getString() { return partOne + partTwo; } CMake.txt add_executable(example1 main.cpp other.cpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -flto") Флаг -flto я вставил для демонстрации того, что даже включение межмодульных оптимизаций не позволяет компилятору убирать какие-либо имена. Соберём проект в режиме Release (-DCMAKE_BUILD_TYPE=Release) и изучим таблицу символов утилитой nm: 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 00406000 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e4 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e4 b .bss 004063e4 b .bss 004063e4 b .bss 00406020 b .bss 004063e4 b .bss 004063e4 b .bss 004063e8 b .bss 004063e4 b .bss 004063e8 b .bss 004063e4 b .bss 004063e4 b .bss 004063e8 b .bss 004063e4 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e0 b .bss 004063c0 b .bss 00406038 b .bss 004063e8 b .bss 004063e8 b .bss 004063c0 b .bss 004063e8 b .bss 00406080 b .bss 00406078 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 00406078 b .bss 00406044 b .bss 0040606c b .bss 004063e8 b .bss 00406044 b .bss 00406068 b .bss 00406068 b .bss 00406044 b .bss 00406068 b .bss 00406064 b .bss 00406064 b .bss 00406044 b .bss 00406064 b .bss 00406044 b .bss 00406060 b .bss 00406060 b .bss 00406044 b .bss 0040605c b .bss 00406058 b .bss 00406044 b .bss 00406054 b .bss 00406044 b .bss 00406044 b .bss 004063e8 b .bss 00406044 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 00408000 d .CRT$XCA 00408004 d .CRT$XCAA 00408008 d .CRT$XCZ 0040802c d .CRT$XDA 00408030 d .CRT$XDZ 0040800c d .CRT$XIA 00408010 d .CRT$XIAA 00408014 d .CRT$XIC 00408018 d .CRT$XIZ 0040801c d .CRT$XLA 00408020 d .CRT$XLC 00408024 d .CRT$XLD 00408028 d .CRT$XLZ 00402914 t .ctors 00402918 t .ctors.65535 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403000 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403020 d .data 00403028 d .data 00403028 d .data 00403020 d .data 00403020 d .data 00403004 d .data 00403020 d .data 00403020 d .data 00403028 d .data 00403028 d .data 00403020 d .data 0040301c d .data 00403028 d .data 0040301c d .data 0040301c d .data 00403028 d .data 00403004 d .data 0040301c d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403004 d .data 0040301c d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403018 d .data 00403028 d .data 00403018 d .data 00403028 d .data 00403028 d .data 00403014 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403004 d .data 00403014 d .data 00403028 d .data 00403014 d .data 00403028 d .data 00403004 d .data 00403014 d .data 00403028 d .data 00403014 d .data 00403004 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403014 d .data 00403014 d .data 0040300c d .data 00403004 d .data 00403004 d .data 00403008 d .data 00403008 d .data 00403008 d .data 00403004 d .data 00403008 d .data 00403004 d .data 00403004 d .data 00403004 d .data 0040301c d .data 00403028 d .data 00403008 d .data 00403028 d .data 00403028 d .data 00403004 d .data 00403028 d .data$__security_cookie 0040302c d .data$__security_cookie_complement 0040c000 N .debug_abbrev 0040c014 N .debug_abbrev 0040a020 N .debug_aranges 0040a000 N .debug_aranges 0040e000 N .debug_frame 0040b0b3 N .debug_info 0040b000 N .debug_info 0040d077 N .debug_line 0040d000 N .debug_line 004055d8 r .eh_frame 00405298 r .eh_frame 004058a0 r .eh_frame 004053e0 r .eh_frame 00405000 r .eh_frame 0040543c r .eh_frame 004053b4 r .eh_frame 004054d0 r .eh_frame 004052c4 r .eh_frame 0040521c r .eh_frame 00405128 r .eh_frame 00405304 r .eh_frame 00405360 r .eh_frame 00405564 r .eh_frame 004054fc r .eh_frame 004050c8 r .eh_frame 004056b0 r .eh_frame 004058e0 r .eh_frame 00402928 t .gcc_except_table 00407028 i .idata$2 00407000 i .idata$2 0040703c i .idata$2 00407014 i .idata$2 00407184 i .idata$4 00407120 i .idata$4 00407130 i .idata$4 00407128 i .idata$4 004070d0 i .idata$4 00407064 i .idata$4 00407168 i .idata$4 0040714c i .idata$4 004070f4 i .idata$4 0040708c i .idata$4 00407094 i .idata$4 004070f0 i .idata$4 00407104 i .idata$4 00407070 i .idata$4 004070c8 i .idata$4 0040716c i .idata$4 004070cc i .idata$4 004070a0 i .idata$4 00407080 i .idata$4 004070e0 i .idata$4 00407138 i .idata$4 004070fc i .idata$4 00407068 i .idata$4 0040709c i .idata$4 00407124 i .idata$4 0040717c i .idata$4 00407064 i .idata$4 00407140 i .idata$4 004070ec i .idata$4 004070b8 i .idata$4 00407158 i .idata$4 0040712c i .idata$4 004070a8 i .idata$4 00407114 i .idata$4 00407148 i .idata$4 00407108 i .idata$4 0040707c i .idata$4 0040711c i .idata$4 004070b0 i .idata$4 00407118 i .idata$4 00407134 i .idata$4 0040713c i .idata$4 00407174 i .idata$4 00407148 i .idata$4 00407164 i .idata$4 00407078 i .idata$4 004070bc i .idata$4 00407180 i .idata$4 004070e8 i .idata$4 00407170 i .idata$4 00407084 i .idata$4 00407098 i .idata$4 00407178 i .idata$4 00407090 i .idata$4 004070b4 i .idata$4 004070c4 i .idata$4 0040706c i .idata$4 00407088 i .idata$4 004070d4 i .idata$4 00407078 i .idata$4 004070d8 i .idata$4 004070c0 i .idata$4 0040715c i .idata$4 00407150 i .idata$4 004070d8 i .idata$4 00407110 i .idata$4 0040710c i .idata$4 00407154 i .idata$4 004070f8 i .idata$4 00407074 i .idata$4 004070e4 i .idata$4 00407160 i .idata$4 00407100 i .idata$4 004070ac i .idata$4 00407144 i .idata$4 004070dc i .idata$4 004070a4 i .idata$4 004071a0 i .idata$5 004071a8 i .idata$5 004071d0 i .idata$5 004071f0 i .idata$5 00407234 i .idata$5 004071e4 i .idata$5 00407278 i .idata$5 00407274 i .idata$5 004071fc i .idata$5 004071ac i .idata$5 00407224 i .idata$5 00407190 i .idata$5 004071d8 i .idata$5 00407200 i .idata$5 00407208 i .idata$5 004071b4 i .idata$5 004071ec i .idata$5 0040719c i .idata$5 0040729c i .idata$5 004071f8 i .idata$5 004071e0 i .idata$5 00407240 i .idata$5 004071fc i .idata$5 00407238 i .idata$5 00407258 i .idata$5 004071e8 i .idata$5 004072a4 i .idata$5 00407298 i .idata$5 004071f4 i .idata$5 00407288 i .idata$5 00407260 i .idata$5 0040720c i .idata$5 004072a0 i .idata$5 00407188 i .idata$5 00407280 i .idata$5 00407290 i .idata$5 00407250 i .idata$5 004071b0 i .idata$5 004071cc i .idata$5 004071dc i .idata$5 00407284 i .idata$5 0040722c i .idata$5 0040718c i .idata$5 0040725c i .idata$5 00407264 i .idata$5 00407248 i .idata$5 00407204 i .idata$5 00407228 i .idata$5 00407194 i .idata$5 004071c0 i .idata$5 0040728c i .idata$5 00407188 i .idata$5 004072a8 i .idata$5 0040726c i .idata$5 00407254 i .idata$5 00407214 i .idata$5 004071c4 i .idata$5 004071a4 i .idata$5 004071b8 i .idata$5 00407218 i .idata$5 00407270 i .idata$5 0040719c i .idata$5 00407244 i .idata$5 00407198 i .idata$5 0040724c i .idata$5 00407210 i .idata$5 004071d4 i .idata$5 0040726c i .idata$5 0040723c i .idata$5 0040721c i .idata$5 00407220 i .idata$5 004071bc i .idata$5 004071c8 i .idata$5 00407294 i .idata$5 00407268 i .idata$5 00407230 i .idata$5 0040727c i .idata$5 00407724 i .idata$6 00407562 i .idata$6 004074d0 i .idata$6 004076a8 i .idata$6 004075a4 i .idata$6 00407374 i .idata$6 0040738a i .idata$6 004072f4 i .idata$6 00407540 i .idata$6 0040759c i .idata$6 00407708 i .idata$6 004077b8 i .idata$6 004075ae i .idata$6 004074a2 i .idata$6 004072c0 i .idata$6 004074fe i .idata$6 004075c0 i .idata$6 00407610 i .idata$6 004073ec i .idata$6 00407324 i .idata$6 00407580 i .idata$6 004075fa i .idata$6 0040751a i .idata$6 0040735e i .idata$6 00407480 i .idata$6 00407790 i .idata$6 004075c8 i .idata$6 00407494 i .idata$6 004074e0 i .idata$6 004074ee i .idata$6 00407674 i .idata$6 0040756c i .idata$6 00407418 i .idata$6 0040750a i .idata$6 00407592 i .idata$6 00407664 i .idata$6 004076e0 i .idata$6 004072dc i .idata$6 0040730c i .idata$6 00407478 i .idata$6 00407604 i .idata$6 004073d2 i .idata$6 00407740 i .idata$6 004075e6 i .idata$6 004075b6 i .idata$6 004073fc i .idata$6 004075d2 i .idata$6 0040745a i .idata$6 00407634 i .idata$6 00407440 i .idata$6 0040754a i .idata$6 004072ac i .idata$6 004076cc i .idata$6 004075f0 i .idata$6 0040733c i .idata$6 0040734a i .idata$6 004074be i .idata$6 004073c0 i .idata$6 004076f8 i .idata$6 00407578 i .idata$6 004075dc i .idata$6 0040739a i .idata$6 00407684 i .idata$6 004073ae i .idata$6 004077ac i .idata$6 00407430 i .idata$6 0040752c i .idata$6 00407558 i .idata$6 00407588 i .idata$6 00407910 i .idata$7 004078a8 i .idata$7 004078a4 i .idata$7 004078f0 i .idata$7 004078e0 i .idata$7 004078e8 i .idata$7 0040791c i .idata$7 004078dc i .idata$7 0040786c i .idata$7 004078b0 i .idata$7 004078c4 i .idata$7 00407858 i .idata$7 00407820 i .idata$7 0040788c i .idata$7 00407934 i .idata$7 00407870 i .idata$7 004078cc i .idata$7 00407924 i .idata$7 00407898 i .idata$7 00407890 i .idata$7 004078a0 i .idata$7 00407834 i .idata$7 00407928 i .idata$7 004078bc i .idata$7 004078ac i .idata$7 004078c8 i .idata$7 00407848 i .idata$7 0040789c i .idata$7 00407804 i .idata$7 004078d4 i .idata$7 004078b8 i .idata$7 004077fc i .idata$7 00407830 i .idata$7 004078ec i .idata$7 004078d8 i .idata$7 00407874 i .idata$7 00407868 i .idata$7 00407888 i .idata$7 00407930 i .idata$7 0040790c i .idata$7 0040782c i .idata$7 00407828 i .idata$7 00407938 i .idata$7 00407850 i .idata$7 004078c0 i .idata$7 004078f4 i .idata$7 00407908 i .idata$7 00407800 i .idata$7 00407894 i .idata$7 0040781c i .idata$7 00407860 i .idata$7 004078e4 i .idata$7 0040792c i .idata$7 0040784c i .idata$7 004077f8 i .idata$7 0040785c i .idata$7 00407918 i .idata$7 00407920 i .idata$7 004078b4 i .idata$7 00407840 i .idata$7 0040793c i .idata$7 00407824 i .idata$7 00407838 i .idata$7 00407914 i .idata$7 00407808 i .idata$7 00407844 i .idata$7 00407854 i .idata$7 00407878 i .idata$7 0040783c i .idata$7 004078d0 i .idata$7 00407904 i .idata$7 00407900 i .idata$7 00407864 i .idata$7 00403030 d .jcr 00403030 d .jcr 00404064 r .rdata 004041ac r .rdata 00404078 r .rdata 004042ac r .rdata 004042a4 r .rdata 00404074 r .rdata 00404000 r .rdata 00404730 r .rdata$zzz 00404370 r .rdata$zzz 004043b0 r .rdata$zzz 004043f0 r .rdata$zzz 00404430 r .rdata$zzz 00404470 r .rdata$zzz 004044b0 r .rdata$zzz 004044f0 r .rdata$zzz 00404530 r .rdata$zzz 004048f0 r .rdata$zzz 00404570 r .rdata$zzz 004045b0 r .rdata$zzz 004045f0 r .rdata$zzz 00404630 r .rdata$zzz 00404670 r .rdata$zzz 004046b0 r .rdata$zzz 00404930 r .rdata$zzz 004046f0 r .rdata$zzz 004048b0 r .rdata$zzz 004042f0 r .rdata$zzz 00404870 r .rdata$zzz 00404770 r .rdata$zzz 004047b0 r .rdata$zzz 004047f0 r .rdata$zzz 004042b0 r .rdata$zzz 00404830 r .rdata$zzz 00404330 r .rdata$zzz 00404970 r .rdata_runtime_pseudo_reloc 004026d8 t .text 004027d0 t .text 00402390 t .text U .text U .text U .text U .text 004026e0 t .text 00402390 t .text 004027c8 t .text 004027d8 t .text 00402140 t .text 00401500 t .text 00402778 t .text U .text 0040270c t .text 004027d8 t .text 00402140 t .text 00402778 t .text 00402780 t .text 00402000 t .text U .text 004026d0 t .text 00402788 t .text 0040270c t .text 004027d8 t .text 00401f60 t .text U .text U .text 00402790 t .text 00401610 t .text 004027a8 t .text 0040270c t .text U .text 004027c0 t .text 00401f50 t .text 0040270c t .text 00402798 t .text 00401b10 t .text U .text U .text 0040270c t .text 00402798 t .text 00401a50 t .text U .text 0040270c t .text 00402714 t .text U .text 00401a40 t .text U .text 00401a40 t .text 00402720 t .text 004018f0 t .text 004027b8 t .text U .text 004018f0 t .text 00402740 t .text 004018f0 t .text 00402748 t .text 004018f0 t .text 00402750 t .text U .text 00401810 t .text 00402758 t .text 00401810 t .text 00402760 t .text 004017f0 t .text 00402768 t .text U .text 004017e0 t .text 004027b0 t .text 00401000 t .text 00401680 t .text U .text 00402770 t .text U .text 00401700 t .text 00401688 t .text 00401690 t .text 00401690 t .text 004016f8 t .text 00401690 t .text U .text 004016f0 t .text U .text 004016e8 t .text 00401698 t .text 004016e0 t .text 004016a0 t .text U .text 004016d8 t .text 004016a8 t .text 004016d0 t .text 004016a8 t .text 004016c8 t .text U .text U .text 004016c0 t .text 004016b0 t .text 004016b8 t .text 004027a0 t .text 004027e0 t .text.startup 004028f0 t .text.startup 00409004 d .tls 00409000 d .tls$AAA 0040901c d .tls$ZZZ 00000000 A .weak.___deregister_frame_info._hmod_libgcc 00000000 A .weak.___register_frame_info._hmod_libgcc 00000000 A .weak.__Jv_RegisterClasses._hmod_libgcc 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 004021c0 T ____w64_mingwthr_add_key_dtor 00402250 T ____w64_mingwthr_remove_key_dtor 004026e0 T ___chkstk_ms 0040800c D ___crt_xc_end__ 00408000 D ___crt_xc_start__ 0040801c D ___crt_xi_end__ 0040800c D ___crt_xi_start__ 0040801c D ___crt_xl_start__ 0040802c D ___crt_xp_end__ 0040802c D ___crt_xp_start__ 0040802c D ___crt_xt_end__ 0040802c D ___crt_xt_start__ 00402910 T ___CTOR_LIST__ 004026d0 T ___deregister_frame_info 00402780 T ___dllonexit 00401f90 T ___do_global_ctors 00401f60 T ___do_global_dtors 00402920 T ___DTOR_LIST__ 00401700 t ___dyn_tls_dtor@12 00401750 T ___dyn_tls_init@12 00404074 R ___dyn_tls_init_callback 004050c8 r ___EH_FRAME_BEGIN__ 004058e0 r ___FRAME_END__ 004015b0 T ___gcc_deregister_frame 00401680 T ___gcc_personality_v0 00401500 T ___gcc_register_frame 00402714 T ___getmainargs 00400000 A ___ImageBase 00403030 d ___JCR_END__ 00403030 d ___JCR_LIST__ 00000000 A ___lconv_init 00401fe0 T ___main 00402630 T ___mingw_enum_import_library_names 00402500 T ___mingw_GetSectionCount 004024b0 T ___mingw_GetSectionForAddress 00401000 t ___mingw_invalidParameterHandler 00406064 B ___mingw_oldexcpt_handler 00408014 D ___mingw_pinit 00401a50 T ___mingw_raise_matherr 00401aa0 T ___mingw_setusermatherr 004022f0 T ___mingw_TLScallback 004063ec B ___mingw_winmain_hInstance 004063e8 B ___mingw_winmain_lpCmdLine 00403000 D ___mingw_winmain_nShowCmd 004063c8 b ___mingwthr_cs 004063c4 b ___mingwthr_cs_init 00402140 t ___mingwthr_run_key_dtors.part.0 00403010 D ___native_dllmain_reason 004063fc B ___native_startup_lock 00406400 B ___native_startup_state 0040300c D ___native_vcclrit_reason 004063f8 B ___onexitbegin 004063f4 B ___onexitend 004026d8 T ___register_frame_info 00401b10 t ___report_error 004020b0 T ___report_gsfailure 00404970 A ___RUNTIME_PSEUDO_RELOC_LIST__ 00404988 R ___RUNTIME_PSEUDO_RELOC_LIST_END__ 00403028 D ___security_cookie 0040302c D ___security_cookie_complement 00402000 T ___security_init_cookie 0040270c T ___set_app_type 00402798 T ___setusermatherr 00401610 t ___tcf_0.lto_priv.6 00401620 t ___tcf_0.lto_priv.7 00401650 t ___tcf_1 004017d0 T ___tlregdtor 00409020 D ___tls_end__ 00409000 D ___tls_start__ 00401180 t ___tmainCRTStartup 00408000 D ___xc_a 00408008 D ___xc_z 0040802c d ___xd_a 00408030 d ___xd_z 0040800c D ___xi_a 00408018 D ___xi_z 0040801c D ___xl_a 00408020 D ___xl_c 00408024 D ___xl_d 00408028 D ___xl_z 00402760 T __amsg_exit 00406414 B __bss_end__ 00406000 B __bss_start__ 00402758 T __cexit 00403004 D __charmax 00403018 D __CRT_MT 00402910 T __CTOR_LIST__ 00403034 D __data_end__ 00403000 D __data_start__ 004017f0 T __decode_pointer 00000000 A __dll__ 00000000 A __dll_characteristics__ 00403008 D __dowildcard 00402920 T __DTOR_LIST__ 00401800 T __encode_pointer 0040a000 D __end__ 00000200 A __file_alignment__ 004023d0 T __FindPESection 00402410 T __FindPESectionByName 00402530 T __FindPESectionExec 0040605c B __fmode 00401f50 T __fpreset 00402898 T __fu0___ZSt4cout 00402720 T __get_invalid_parameter_handler 004025a0 T __GetPEImageBase 004027e0 t __GLOBAL__I_65535_0_objects.a_0xd0.3181 004018f0 T __gnu_exception_handler@4 00407014 I __head_lib32_libkernel32_a 00407028 I __head_lib32_libmsvcrt_a 00407000 I __head_libgcc_s_dw2_1_dll 0040703c I __head_libstdc___6_dll 004072ac I __IAT_end__ 00407188 I __IAT_start__ 00400000 A __image_base__ 0040718c I __imp____deregister_frame_info 004071fc I __imp____dllonexit 00407190 I __imp____gcc_personality_v0 00407200 I __imp____getmainargs 00407204 I __imp____initenv 00407208 I __imp____lconv_init 00407194 I __imp____register_frame_info 0040720c I __imp____set_app_type 00407210 I __imp____setusermatherr 00407214 I __imp___acmdln 00407218 I __imp___amsg_exit 0040721c I __imp___cexit 00407220 I __imp___fmode 00403020 D __imp___get_invalid_parameter_handler 00407224 I __imp___initterm 00407228 I __imp___iob 0040722c I __imp___lock 00407230 I __imp___onexit 00403024 D __imp___set_invalid_parameter_handler 00407234 I __imp___unlock 00407188 I __imp___Unwind_Resume 0040726c I __imp___ZNKSt5ctypeIcE13_M_widen_initEv 00407270 I __imp___ZNKSt9basic_iosIcSt11char_traitsIcEE5widenEc 00407274 I __imp___ZNSo3putEc 00407278 I __imp___ZNSo5flushEv 0040727c I __imp___ZNSs4_Rep10_M_destroyERKSaIcE 00407280 I __imp___ZNSs4_Rep10_M_disposeERKSaIcE 00407284 I __imp___ZNSs6appendERKSs 00407288 I __imp___ZNSsC1EPKcRKSaIcE 0040728c I __imp___ZNSsC1ERKSs 00407290 I __imp___ZNSt8ios_base4InitC1Ev 00407294 I __imp___ZNSt8ios_base4InitD1Ev 00407298 I __imp___ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i 0040729c I __imp___ZSt16__throw_bad_castv 004072a0 I __imp___ZSt4cout 004072a0 I __imp___ZSt4cout 004072a4 I __imp___ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 00407238 I __imp__abort 0040723c I __imp__calloc 0040719c I __imp__DeleteCriticalSection@4 004071a0 I __imp__EnterCriticalSection@4 00407240 I __imp__exit 00407244 I __imp__fprintf 00407248 I __imp__free 004071a4 I __imp__FreeLibrary@4 0040724c I __imp__fwrite 004071a8 I __imp__GetCurrentProcess@0 004071ac I __imp__GetCurrentProcessId@0 004071b0 I __imp__GetCurrentThreadId@0 004071b4 I __imp__GetLastError@0 004071b8 I __imp__GetModuleHandleA@4 004071bc I __imp__GetProcAddress@8 004071c0 I __imp__GetStartupInfoA@4 004071c4 I __imp__GetSystemTimeAsFileTime@4 004071c8 I __imp__GetTickCount@0 004071cc I __imp__InitializeCriticalSection@4 004071d0 I __imp__LeaveCriticalSection@4 004071d4 I __imp__LoadLibraryA@4 00407250 I __imp__malloc 00407254 I __imp__memcpy 004071d8 I __imp__QueryPerformanceCounter@4 004071dc I __imp__SetUnhandledExceptionFilter@4 00407258 I __imp__signal 004071e0 I __imp__Sleep@4 0040725c I __imp__strlen 00407260 I __imp__strncmp 004071e4 I __imp__TerminateProcess@8 004071e8 I __imp__TlsGetValue@4 004071ec I __imp__UnhandledExceptionFilter@4 00407264 I __imp__vfprintf 004071f0 I __imp__VirtualProtect@16 004071f4 I __imp__VirtualQuery@12 00402768 T __initterm 004025d0 T __IsNonwritableInCurrentImage U __Jv_RegisterClasses 00407878 I __lib32_libkernel32_a_iname 004078f4 I __lib32_libmsvcrt_a_iname 00000000 A __loader_flags__ 00402778 T __lock 00000000 A __major_image_version__ 00000004 A __major_os_version__ 00000004 A __major_subsystem_version__ 00401ab0 T __matherr 0040301c D __MINGW_INSTALL_DEBUG_MATHERR 00000000 A __minor_image_version__ 00000000 A __minor_os_version__ 00000000 A __minor_subsystem_version__ 00406060 B __newmode 004077ac I __nm___ZSt4cout 00401cb0 T __pei386_runtime_relocator 00404988 R __rt_psrelocs_end 00000018 A __rt_psrelocs_size 00404970 R __rt_psrelocs_start 00404970 A __RUNTIME_PSEUDO_RELOC_LIST__ 00404988 R __RUNTIME_PSEUDO_RELOC_LIST_END__ 00001000 A __section_alignment__ 00402730 T __set_invalid_parameter_handler 00401a40 T __setargv 00001000 A __size_of_heap_commit__ 00100000 A __size_of_heap_reserve__ 00001000 A __size_of_stack_commit__ 00200000 A __size_of_stack_reserve__ 00000003 A __subsystem__ 0040901c D __tls_end 00406050 B __tls_index 00409000 D __tls_start 00409004 D __tls_used 00402788 T __unlock 00401688 T __Unwind_Resume 004023b0 T __ValidateImageBase 00402390 t __ValidateImageBase.part.0 00000000 A __Z9getStringv 00406038 b __ZL7partTwo 004016c8 T __ZNKSt5ctypeIcE13_M_widen_initEv 00000000 A __ZNKSt5ctypeIcE8do_widenEc 00401698 T __ZNKSt9basic_iosIcSt11char_traitsIcEE5widenEc 004016e0 T __ZNSo3putEc 004016d8 T __ZNSo5flushEv 004016a8 T __ZNSs4_Rep10_M_destroyERKSaIcE 00401690 T __ZNSs4_Rep10_M_disposeERKSaIcE 004016f0 T __ZNSs6appendERKSs 004016b0 T __ZNSsC1EPKcRKSaIcE 004016f8 T __ZNSsC1ERKSs 004016b8 T __ZNSt8ios_base4InitC1Ev 004016c0 T __ZNSt8ios_base4InitD1Ev 004016e8 T __ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i 004016d0 T __ZSt16__throw_bad_castv 004016a0 T __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 00406040 b __ZStL8__ioinit 00000000 A __ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_ 004027b8 T _abort 0040601c b _argc 00406010 b _argret 00406018 b _argv 004018d0 T _atexit 004027c0 T _calloc 00404194 r _CSWTCH.5 00000000 A _DeleteCriticalSection@4 00000000 A _EnterCriticalSection@4 00406014 b _envp 00402770 T _exit 00401f50 T _fpreset 004027a0 T _fprintf 004027c8 T _free 00000000 A _FreeLibrary@4 004027a8 T _fwrite 00000000 A _GetCurrentProcess@0 00000000 A _GetCurrentProcessId@0 00000000 A _GetCurrentThreadId@0 00000000 A _GetLastError@0 00000000 A _GetModuleHandleA@4 00000000 A _GetProcAddress@8 00000000 A _GetStartupInfoA@4 00000000 A _GetSystemTimeAsFileTime@4 00000000 A _GetTickCount@0 00406080 b _GS_ContextRecord 004042a4 r _GS_ExceptionPointers 00406360 b _GS_ExceptionRecord 004063e4 b _handler 00406004 b _has_cctor 004063f0 B _hmod_libgcc 00000000 A _InitializeCriticalSection@4 00406078 b _initialized 004063c0 b _key_dtor_list 00000000 A _LeaveCriticalSection@4 00407808 I _libgcc_s_dw2_1_dll_iname 0040793c I _libstdc___6_dll_iname 00000000 A _LoadLibraryA@4 00402850 T _main 004014e0 T _mainCRTStartup 0040600c b _mainret 00402740 T _malloc 00406008 b _managedapp 00401b70 t _mark_section_writable 00406070 b _maxSections 00402750 T _memcpy 00406058 B _mingw_app_type 00402720 t _mingw_get_invalid_parameter_handler 00406054 B _mingw_initcharmax 0040604c B _mingw_initltsdrot_force 00406048 B _mingw_initltsdyn_force 00406044 B _mingw_initltssuo_force 00401810 T _mingw_onexit 00408010 D _mingw_pcinit 00408004 D _mingw_pcppinit 00402730 t _mingw_set_invalid_parameter_handler 004017e0 t _my_lconv_init 00406020 b _obj 00403014 d _p.59329 0040603c b _partOne 00000000 A _partOne 00401010 t _pre_c_init 00401130 t _pre_cpp_init 00000000 A _QueryPerformanceCounter@4 004028f0 t _register_frame_ctor 00000000 A _SetUnhandledExceptionFilter@4 00402790 T _signal 00000000 A _Sleep@4 00406000 b _startinfo 00402748 T _strlen 004027d0 T _strncmp 00406068 b _stUserMathErr 00000000 A _TerminateProcess@8 00406074 b _the_secs 00000000 A _TlsGetValue@4 00000000 A _UnhandledExceptionFilter@4 004027b0 T _vfprintf 00000000 A _VirtualProtect@16 00000000 A _VirtualQuery@12 0040606c b _was_init.60615 004014c0 T _WinMainCRTStartup 004071fc i fthunk 0040719c i fthunk 00407078 i hname 004070d8 i hname Не кажется, что это как-то слишком много для программы, которая ничего не экспортирует в духе DLL? Заодно запомним размер программы: 52 105 байт. Теперь несколько изменим CMakeList.txt: add_executable(example2 main.cpp other.cpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -flto -s") Мы добавили флаг -s и изменили имя исполняемого файла. Теперь после сборки программы nm выдаёт следующее: nm: example2.exe: no symbols То есть программе для работы не требуется ни одно из 1 001 вышеупомянутого имени! А что с объёмом? 16 896 байт. То есть мы смогли безболезненно уменьшить размер программы в три раза! И это для двух простых объектных файлов. При усложнении же проекта доля имён от размера исполняемого файла будет ещё больше. Кстати, вы заметили, что бо́льшую часть символов занимают имена секций? Так вот, это следствие различия форматов объектных (ELF) и исполняемых (PE EXE) файлов при сборке под MinGW, не позволяющего объединить эти имена и использовать их по прямому назначению. Также в таблице имён фигурирует большое количество символов из объектных файлов стандартной библиотеки. При написании данного ответа использовались следующие версии программ: CMake 3.4.0, GCC 4.9.2 (i686-posix-dwarf-rev1, Built by MinGW-W64 project), GNU nm (GNU Binutils) 2.24.

пятница, 27 декабря 2019 г.

Как связать ассемблерный код вместе с C\С++ для запуска в DosBox с прерываниями?

#c #компоновщик #cpp #ассемблер


asm(".code16gcc\n");
#define G640x350x64c 0x10
#define T80x25 0x3
#define R320x200x16c 0xD
void setVMode(int mode);
int _main() {
setVmode(G640x350x64c);
return 0;
}
void setVMode(int mode) {
asm("mov ah,0");
asm("mov al,byte ptr[ebp+0x8]");
asm("int 0x10");
}

Итак, этот код рабочий, и он меняет видеорежим в консоли. Запускается в досбоксе,
предварительно скомпилированный таким образом: 
gсс -O0 -c  -masm=intel main.c -o main.o
ld main.o -o prog.com
objcopy prog.com -O binary
C:\Progra~1\DOSBox-0.74\DOSBox.exe

Т.е. создается бинарник, независимый от системы. И вот тут начинаются проблемы, если
добавить какую-нибудь библиотечную функцию, ld автоматически не линкует библиотеки
типа stdlib и прочих. Использование автоматической линковки с помощью  gcc к успеху
не приведет, нужен чистый бинарник, свободный от системной информации.    


Ответы

Ответ 1



Нужно либо писать сразу в интел асме этот код и обращаться к библиотекам там (наверняка у вас интел асм), либо использовать другой способ внедрения asm -- тот что используется в gcc без пропускания данных через masm

Изменить сегмент в ld

#c #gcc #компоновщик #ld


По умолчанию ld, как я понял, считает, что в %ds находится 0 и соответственно компонует
программу на языке C с этим значением. Как его изменить в настройках компоновщика,
чтобы при изменении %ds на другое значение в программе (например, 0x07c0), она работала
корректно?

На всякий случай уточню, что речь идёт о написании программы наподобие загрузчика.  
    


Ответы

Ответ 1



Как я понял, напрямую задать %ds нельзя, но зато для секции .data можно указать VMA, что расшифровывается, как Virtual Memory Address. После этого, компоновщик будет загружать секцию по LMA (Load Memory Address), но адреса переменных, находящихся в этой секции, при обращении к этим переменным из программы, будут начинаться с VMA, а не с LMA. Рассмотрим такой пример: в %ds устанавливается в коде значение 0x07c0, секция .text загружается по адресу 0x7c00, .data находится сразу после .text. Тогда необходимо установить VMA равным размеру секции .text. После этого, например, переменная, находящаяся в самом начале секции .data, при обращении к ней из кода программы, будет иметь адрес %ds*16+Размер секции .text=0x7c00+Размер секции .text. Это соответствует фактическому расположению переменной. Полный код скрипта компоновщика: ENTRY(main); SECTIONS { . = 0x7C00; /*установлен только LMA, VMA такой же */ .text : AT(0x7C00) { _text = .; *(.text*); _text_end = .; } /*VMA=SIZEOF(.text) LMA=ADDR (.text) + SIZEOF (.text)*/ .data (SIZEOF(.text)) : AT(ADDR (.text) + SIZEOF (.text)) { _data = .; *(.bss); *(.bss*); *(.data); *(.rodata*); *(COMMON) _data_end = .; } .sig : AT(0x7DFE) { SHORT(0xaa55); } /DISCARD/ : { *(.note*); *(.iplt*); *(.igot*); *(.rel*); *(.comment); *(.eh_frame); } } Подробнее про LMA и VMA можно почитать по этой ссылке https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html

понедельник, 23 декабря 2019 г.

C++: Undefined reference при линковке теста с либой

#cpp #шаблоны_с++ #компоновщик #clang


Вот исходник тесты

#include 
#include 
using namespace RFw;

int main() {
    Array _a_;

    _a_.resize(5);

    _a_[2] = 'b';
    _a_[3] = 'a';

    printf("%c%c\n", *(_a_.provideElement(2)), *(_a_.provideElement(3)));

    return 0;
}

Так компилю:

c++ test.cpp -o test -std=c++11 -Isrc-core/ -Lbin/ -lcore

Вывод:

/tmp/test-k6aFM8.o: In function `main':                                         
                                                                                  
                                                 
test.cpp.text+0x27): undefined reference to `RFw::Array::Array(unsigned int,
int*)'                                                                            
                                              
test.cpp.text+0x3a): undefined reference to `RFw::Array::resize(unsigned int)'
                                                                                  
                                            
test.cpp:(.text+0x52): undefined reference to `RFw::Array::operator[](unsigned
int)'                                                                             
                                              
test.cpp:(.text+0x76): undefined reference to `RFw::Array::operator[](unsigned
int)'                                                                             
                                              
test.cpp:(.text+0x9a): undefined reference to `RFw::Array::provideElement(unsigned
int)'
test.cpp:(.text+0xbd): undefined reference to `RFw::Array::provideElement(unsigned
int)'
test.cpp:(.text+0x101): undefined reference to `RFw::Array::~Array()'
test.cpp:(.text+0x11b): undefined reference to `RFw::Array::~Array()'
clang: error: linker command failed with exit code 1 (use -v to see invocation)

PS Array взят из Array.hpp который инклюдится в common.hpp
Array.hpp:

/**
 *      src-core/Array.hpp
 */
#ifndef _ARRAY_HPP_
#define _ARRAY_HPP_

#include "util.hpp"
#include "Object.hpp"
#include "arrayExceptions.hpp"

namespace RFw {
    template
    class Array : public Object {
    public:
                                Array(intnum _length = 0, TValue* _array = nullptr);
        virtual                 ~Array();

        void                    addToTop(const TValue _element) throw(ArrayOverflowException);
        void                    addToEnd(const TValue _element) throw(ArrayOverflowException);
        void                    clone(const intnum _length, const TValue* _array);

        TValue*                 provideElement(const intnum _index) throw(IndexOutOfRangeException);
        const TValue*           provideElement(const intnum _index) const throw(IndexOutOfRangeException);

        TValue&                 operator[](const intnum _index) throw(IndexOutOfRangeException);
        const TValue&           operator[](const intnum _index) const throw(IndexOutOfRangeException);

        void                    resize(const intnum _newLentgh);

        const Array     getClone() const;
        const intnum            getLength() const;
        const TValue*           getArray() const;
    private:
        intnum                  length__;
        TValue*                 array__;
    };
}

#endif //   _ARRAY_HPP_
    


Ответы

Ответ 1



С шаблонами вы должны помещать реализацию методов в header. В вашем случае пишите так: template class Array : public Object { public: Array(intnum _length = 0, TValue* _array = nullptr) : length__(_length), array__(new TValue[_length]) { // остаток имплементации } virtual ~Array() { delete[] array__; } // и так далее }; Если вы вынесете реализацию методов в .cpp-файл, компилятор не будет знать, какие инстанциации шаблона ему нужно компилировать. Это ограничение модели компиляции языка C++. Sorry for this. Небольшое объяснение. В C++ шаблон не есть класс, это лишь «описание», по которому при подстановке шаблонных аргументов генерируется реальный класс. Никакого объектного кода шаблон сам по себе не производит. Когда компилятор компилирует C++-файл с кодом, использующим шаблон, он видит, с каким шаблонным аргументом используется этот шаблон. Но когда он компилирует C++-файл с реализацией шаблонных методов, он не знает, с какими аргументами инстанциировался шаблон в других файлах, ведь каждый C++-файл компилируется по отдельности! Поэтому решением является положить реализацию внутрь шаблонного класса. При этом компилятор в той точке, где он видит инстанциацию шаблона, видит весь его код, и может скомпилировать все методы класса. (Существует ещё уродливый костыль с указанием в C++-файле точного списка инстанциаций шаблона, который настолько ужасен, что я не хочу о нём и говорить. Аналогом этому было бы около каждой функции указывать заранее список всех аргументов, с которым функция будет вызвана в программе.)

понедельник, 16 декабря 2019 г.

Как работает компоновка С-приложений?

#c #dll #компиляция #lib #компоновщик


Компилятор выполняет сборку объектных файлов (.obj) в каждом из которых (в начале?)
содержится таблица символов, где хранится все глобальные переменные, их значения (если
они есть) и адреса объявленных функции. Что же представляет собой остальное содержимое
объектного файла? Скомпилированный код. Как он выглядит, если у нас несколько функций?
Не сливается же это всё в единую последовательность команд...

Как устроена статическая линковка библиотек? Неразрешённые символы таблицы символов
компоновщик ищет в указанных библиотеках. Так понимаю, в библиотеке тоже должно быть
указано где находится искомая функция и её размер. Далее функция включается в исполняемый
файл. Выходит, .lib не нужно за собой таскать раз функция уже в .exe?

Как устроена динамическая линковка библиотек? ОС должна используя таблицу импорта
найти нужные функции в .dll и загрузить эти функции в оперативную память процесса?

Пожалуйста, можно объяснить поподробнее обо всех этих вещах и том, что посчитаете
относящимся к этому вопросу.



CORRECTED: Уточняю свои вопросы:


Объектные файлы. Компилятор выполняет создание объектного файла, который в общем
виде представлен заголовком, содержащим различную информацию о программе, и скомпилированным
кодом, который так же зависит от RTL и, в зависимости от компилятора, содержит те или
иные ссылки на функции из библиотек RTL. Заголовок так же содержит таблицу символов
(где находится информация обо всех методах и глобальных переменных (размер, тип, адреса
и т.п.), а так же, в случае С++, описания методов классов, запись названий которых
осуществляется при помощи декорирования имён ввиду некоторых ограничений на символы
(в случае dll, это затрудняет использование классов при явной компоновке, как я понял)).
Скомпилированный код просто представлен сплошными инструкциями, которые как-то разделяются
по функциям, на начала которых указывают символы в таблице символов. Когда объектных
файлов несколько, таблицы символов сливаются, как и код, а из повторяющихся символов
выбирается самый "массивный". Верно ли? Чем вы можете дополнить это?.
Статическая компоновка. Неразрешённые символы из таблицы символов объектного файла
компоновщик ищет в подключаемых библиотеках. В случае статической компоновки .lib файл
используется лишь как ресурс для функций, откуда копируются в целевой .exe их содержимое
(т.е. .lib за собой таскать не надо?).
Динамическая компоновка. При динамической линковке, компоновщик помечает неразрешённые
символы как IOU ("я тебе должен") (ищет ли он их определения в указанных .dll? надо
же быть уверенным, что такая .dll, которую указал пользователь вообще существует и
в ней есть этот метод. Разве нет?). При запуске .exe ОС подключает нужные .dll (ищет
их в нужных местах) и загружает в память. Только, вроде как, при неявной компоновке
если какая-то .dll уже есть в памяти, она не будет загружена снова. Но как ОС знает
по какому адресу эта .dll загружена? Методы заменяются на ссылки на функции загруженной
.dll или как? При явной загрузке все функции .dll вроде просто выгружаются в память
на ровне с функциями самого .exe и в таблице данных есть адреса этих функций в оперативной
памяти - или как это вообще выглядит? При передаче переменной в метод её имя заменяется
на адрес из блока данных? Как это выглядит?

    


Ответы

Ответ 1



Извините конечно, но на тему ваших вопросов можно целую книгу написать... Если очень грубо, то формат объектного файла в целом описывается стандартом ELF - Executable & Linkable File - по сути это файл с неким заголовком и произвольным набором секций, именование секций вообще говоря зависит от платформы. Для старых Windows программ формат объектных файлов описывается COFF - Common Object File Format - структурно формат схож с ELF, но он более Windows ориентирован, в то время как ELF - кроссплатформенный. Если охота поразбираться в кишках - то велкам сюда

суббота, 30 ноября 2019 г.

Чем плохи большие размеры исполняемых файлов?

#cpp #оптимизация #сборка #компоновщик


Уже не раз видел ответы людей по типу: 


  -О3 генерирует быстрый, но раздутый исполняемый файл





  LTO помогает этот раздутый код уменьшить





  Шаблоны С++ приводят к распуханию исполняемого файла, это плохо


или 


  Используй компоновщик gold вместо gnu-ld, он собирает меньший по размеру исполняемый
файл... 


Каждая из приведенных фраз это, конечно, целая дискуссия, но у всех одна цель - уменьшить
размер бинарного файла. 

Объясните, пожалуйста, почему так важно иметь как можно меньший по размеру бинарный
файл? Связано ли это со скоростью загрузки приложения, кэша инструкций процессора,
или еще с чем-то?
    


Ответы

Ответ 1



Для начала предлагаю отвлечься от слова "исполняемый" и рассмотреть просто файл. Что значит большой размер? Файл потребует больше места для хранения, он дольше будет копироваться или как-то иначе обрабатываться, когда речь идет об обработке его содержимого, а не просто имени или даты создания. В таких случаях часто прибегают к механизмам дополнительного сжатия информации, проще говоря, архивированию. Это уменьшит размер и время копирования, но для последующей обработки, вероятнее всего, придется выполнить распаковку, что может в итоге даже увеличить время обработки по сравнению с несжатым файлом. Теперь, чем отличается исполняемый файл от обычного? Он так или иначе содержит код, набор инструкций, которые должен выполнить (обработать) процессор. Понятно, что размер программы зависит от предоставляемого функционала, и наращивание логики приведет к увеличению размера. В большинстве случаев это не является проблемой, так как диски становятся всё больше, память и процессоры быстрее, а архитектурные решения опираются на декомпозицию: разделение кода на модули/библиотеки и подгрузку кода по мере необходимости. Но в некоторых ситуациях, например, в микроконтроллерах ресурсы серьезно ограничены и там идет борьба за размер, и использование разных техник оптимизации. Кстати, для исполняемых файлов тоже существуют архиваторы, один из них, это UPX.

Ответ 2



-О3 генерирует быстрый, но раздутый исполняемый файл По нынешним временам для большинства задач скорость более критична чем размер файла. Если код быстрый (все инлайн подстановки выполнены, многие циклы развернуты, все инварианты вынесены из циклов) то больше ничего от кода и не надо. Ребята, которые пишут оптимизаторы, не зря едят свои гамбургеры. Если нужен БЫСТРЫЙ код, то следует применять оптимизацию. шаблоны c++ приводят к распуханию исполняемого файла Это утверждение более чем спорно. Если шаблоны нужны в данной задаче, то они никак не увеличивают код по сравнению с ручным переписыванием классов с незначительными изменениями. В любом случае инстанцирование шаблона в С++ вполне прозрачно и всегда понятно, во что компилятор развернет шаблон. UPD1: Для микроконтроллеров теоретически есть проблема размера бинарника но и там память дешевле чем скорость даже более чем на десктопах и серверах. Так что если на микроконтроллере бинарник не влезает в память, то это показатель плохого дизайна системы. Всегда проще и дешевле поставить лишний чип памяти, а вот добавить лишних терафлопсов это уже совсем другие деньги.

четверг, 11 июля 2019 г.

VS15 библиотеки компоновщика

Каждый раз когда делаю новый проект приходится прописывать библиотеки для opengl
glaux.lib glu32.lib glui32.lib glut32.lib opengl32.lib
Как сделать чтобы эти библиотеки были по умолчанию в компоновщике Visual Studio


Ответ

Для этого существуют Property Sheets. Я записал gif-ку. Сначала откройте окно Property Manager в Visual Studio. (Edit->Other windows->Property manager).
Затем нажмите Add New Project Property Sheet. Введите имя (скажем, "Opengl") и сохраните в какой-нибудь удобной для вас директории (общей для всех проектов). В дереве Property Manager появится новый Property Sheet "Opengl". Откройте его свойства и добавьте нужные библиотеки в опции линкера. Сохраните настройки.
Теперь вы можете использовать полученный Opengl.props во всех новых проектах. После создания нового проекта, вам надо будет открыть Property Manager и нажать Add Existing Property Sheet.
Вы также можете редактировать дефолтные Property Sheets (например, Microsoft.Cpp.Win32.user) и тогда эти библиотеки будут подключаться ко всем проектам на C++ по умолчанию, но это не рекомендуется.

вторник, 12 февраля 2019 г.

Для чего нужен флаг -s в gcc?

Собственно ответ на вопрос я нашел:
Remove all symbol table and relocation information from the executable. (https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html#Link-Options)
Нашел статью о relocation information
relocation information настроечная информация (информация для компоновщика о том, какие конструкции в объектном файле должны быть заменены адресами объектов, определенных в других исходных файлах) (http://computer_en_ru.academic.ru/36046/relocation_information)
Затем нашел ответ на вопрос, что за symbol table такая: https://stackoverflow.com/questions/69112/what-is-a-symbol-table
Но с моим знанием английского целостный взгляд на проблему так и не сложился. Может кто-то поможет собрать все части пазла в единую картину?


Ответ

Компилятор помещает в исполняемый файл не только то, что нужно для запуска (то есть код и данные), но ещё и дополнительную (и в общем-то ненужную) информацию (к примеру, имена всех переменных и функций, включая те, что были объявлены со спецификатором static).
Эта дополнительная информация нужна только на стадии компоновки, но компилятор оставляет её и в конечном исполняемом файле, возможно для удобства дальнейшей отладки. За её вырезание и отвечает флаг -s
Возьмём, к примеру, программу, состоящую из двух файлов исходных кодов:
main.cpp
#include #include
std::string partOne("Hello, "); // Глобальная переменная
std::string getString(); // Прототип функции, объявленной в другом файле
int main() { std::cout << getString() << std::endl; return 0; } other.cpp
#include
extern std::string partOne; static std::string partTwo("World!");
std::string getString() { return partOne + partTwo; } CMake.txt
add_executable(example1 main.cpp other.cpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -flto")
Флаг -flto я вставил для демонстрации того, что даже включение межмодульных оптимизаций не позволяет компилятору убирать какие-либо имена.
Соберём проект в режиме Release (-DCMAKE_BUILD_TYPE=Release) и изучим таблицу символов утилитой nm
004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 00406000 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e4 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e4 b .bss 004063e4 b .bss 004063e4 b .bss 00406020 b .bss 004063e4 b .bss 004063e4 b .bss 004063e8 b .bss 004063e4 b .bss 004063e8 b .bss 004063e4 b .bss 004063e4 b .bss 004063e8 b .bss 004063e4 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e0 b .bss 004063c0 b .bss 00406038 b .bss 004063e8 b .bss 004063e8 b .bss 004063c0 b .bss 004063e8 b .bss 00406080 b .bss 00406078 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 00406078 b .bss 00406044 b .bss 0040606c b .bss 004063e8 b .bss 00406044 b .bss 00406068 b .bss 00406068 b .bss 00406044 b .bss 00406068 b .bss 00406064 b .bss 00406064 b .bss 00406044 b .bss 00406064 b .bss 00406044 b .bss 00406060 b .bss 00406060 b .bss 00406044 b .bss 0040605c b .bss 00406058 b .bss 00406044 b .bss 00406054 b .bss 00406044 b .bss 00406044 b .bss 004063e8 b .bss 00406044 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 004063e8 b .bss 00408000 d .CRT$XCA 00408004 d .CRT$XCAA 00408008 d .CRT$XCZ 0040802c d .CRT$XDA 00408030 d .CRT$XDZ 0040800c d .CRT$XIA 00408010 d .CRT$XIAA 00408014 d .CRT$XIC 00408018 d .CRT$XIZ 0040801c d .CRT$XLA 00408020 d .CRT$XLC 00408024 d .CRT$XLD 00408028 d .CRT$XLZ 00402914 t .ctors 00402918 t .ctors.65535 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403000 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403020 d .data 00403028 d .data 00403028 d .data 00403020 d .data 00403020 d .data 00403004 d .data 00403020 d .data 00403020 d .data 00403028 d .data 00403028 d .data 00403020 d .data 0040301c d .data 00403028 d .data 0040301c d .data 0040301c d .data 00403028 d .data 00403004 d .data 0040301c d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403004 d .data 0040301c d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403018 d .data 00403028 d .data 00403018 d .data 00403028 d .data 00403028 d .data 00403014 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403004 d .data 00403014 d .data 00403028 d .data 00403014 d .data 00403028 d .data 00403004 d .data 00403014 d .data 00403028 d .data 00403014 d .data 00403004 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403028 d .data 00403014 d .data 00403014 d .data 0040300c d .data 00403004 d .data 00403004 d .data 00403008 d .data 00403008 d .data 00403008 d .data 00403004 d .data 00403008 d .data 00403004 d .data 00403004 d .data 00403004 d .data 0040301c d .data 00403028 d .data 00403008 d .data 00403028 d .data 00403028 d .data 00403004 d .data 00403028 d .data$__security_cookie 0040302c d .data$__security_cookie_complement 0040c000 N .debug_abbrev 0040c014 N .debug_abbrev 0040a020 N .debug_aranges 0040a000 N .debug_aranges 0040e000 N .debug_frame 0040b0b3 N .debug_info 0040b000 N .debug_info 0040d077 N .debug_line 0040d000 N .debug_line 004055d8 r .eh_frame 00405298 r .eh_frame 004058a0 r .eh_frame 004053e0 r .eh_frame 00405000 r .eh_frame 0040543c r .eh_frame 004053b4 r .eh_frame 004054d0 r .eh_frame 004052c4 r .eh_frame 0040521c r .eh_frame 00405128 r .eh_frame 00405304 r .eh_frame 00405360 r .eh_frame 00405564 r .eh_frame 004054fc r .eh_frame 004050c8 r .eh_frame 004056b0 r .eh_frame 004058e0 r .eh_frame 00402928 t .gcc_except_table 00407028 i .idata$2 00407000 i .idata$2 0040703c i .idata$2 00407014 i .idata$2 00407184 i .idata$4 00407120 i .idata$4 00407130 i .idata$4 00407128 i .idata$4 004070d0 i .idata$4 00407064 i .idata$4 00407168 i .idata$4 0040714c i .idata$4 004070f4 i .idata$4 0040708c i .idata$4 00407094 i .idata$4 004070f0 i .idata$4 00407104 i .idata$4 00407070 i .idata$4 004070c8 i .idata$4 0040716c i .idata$4 004070cc i .idata$4 004070a0 i .idata$4 00407080 i .idata$4 004070e0 i .idata$4 00407138 i .idata$4 004070fc i .idata$4 00407068 i .idata$4 0040709c i .idata$4 00407124 i .idata$4 0040717c i .idata$4 00407064 i .idata$4 00407140 i .idata$4 004070ec i .idata$4 004070b8 i .idata$4 00407158 i .idata$4 0040712c i .idata$4 004070a8 i .idata$4 00407114 i .idata$4 00407148 i .idata$4 00407108 i .idata$4 0040707c i .idata$4 0040711c i .idata$4 004070b0 i .idata$4 00407118 i .idata$4 00407134 i .idata$4 0040713c i .idata$4 00407174 i .idata$4 00407148 i .idata$4 00407164 i .idata$4 00407078 i .idata$4 004070bc i .idata$4 00407180 i .idata$4 004070e8 i .idata$4 00407170 i .idata$4 00407084 i .idata$4 00407098 i .idata$4 00407178 i .idata$4 00407090 i .idata$4 004070b4 i .idata$4 004070c4 i .idata$4 0040706c i .idata$4 00407088 i .idata$4 004070d4 i .idata$4 00407078 i .idata$4 004070d8 i .idata$4 004070c0 i .idata$4 0040715c i .idata$4 00407150 i .idata$4 004070d8 i .idata$4 00407110 i .idata$4 0040710c i .idata$4 00407154 i .idata$4 004070f8 i .idata$4 00407074 i .idata$4 004070e4 i .idata$4 00407160 i .idata$4 00407100 i .idata$4 004070ac i .idata$4 00407144 i .idata$4 004070dc i .idata$4 004070a4 i .idata$4 004071a0 i .idata$5 004071a8 i .idata$5 004071d0 i .idata$5 004071f0 i .idata$5 00407234 i .idata$5 004071e4 i .idata$5 00407278 i .idata$5 00407274 i .idata$5 004071fc i .idata$5 004071ac i .idata$5 00407224 i .idata$5 00407190 i .idata$5 004071d8 i .idata$5 00407200 i .idata$5 00407208 i .idata$5 004071b4 i .idata$5 004071ec i .idata$5 0040719c i .idata$5 0040729c i .idata$5 004071f8 i .idata$5 004071e0 i .idata$5 00407240 i .idata$5 004071fc i .idata$5 00407238 i .idata$5 00407258 i .idata$5 004071e8 i .idata$5 004072a4 i .idata$5 00407298 i .idata$5 004071f4 i .idata$5 00407288 i .idata$5 00407260 i .idata$5 0040720c i .idata$5 004072a0 i .idata$5 00407188 i .idata$5 00407280 i .idata$5 00407290 i .idata$5 00407250 i .idata$5 004071b0 i .idata$5 004071cc i .idata$5 004071dc i .idata$5 00407284 i .idata$5 0040722c i .idata$5 0040718c i .idata$5 0040725c i .idata$5 00407264 i .idata$5 00407248 i .idata$5 00407204 i .idata$5 00407228 i .idata$5 00407194 i .idata$5 004071c0 i .idata$5 0040728c i .idata$5 00407188 i .idata$5 004072a8 i .idata$5 0040726c i .idata$5 00407254 i .idata$5 00407214 i .idata$5 004071c4 i .idata$5 004071a4 i .idata$5 004071b8 i .idata$5 00407218 i .idata$5 00407270 i .idata$5 0040719c i .idata$5 00407244 i .idata$5 00407198 i .idata$5 0040724c i .idata$5 00407210 i .idata$5 004071d4 i .idata$5 0040726c i .idata$5 0040723c i .idata$5 0040721c i .idata$5 00407220 i .idata$5 004071bc i .idata$5 004071c8 i .idata$5 00407294 i .idata$5 00407268 i .idata$5 00407230 i .idata$5 0040727c i .idata$5 00407724 i .idata$6 00407562 i .idata$6 004074d0 i .idata$6 004076a8 i .idata$6 004075a4 i .idata$6 00407374 i .idata$6 0040738a i .idata$6 004072f4 i .idata$6 00407540 i .idata$6 0040759c i .idata$6 00407708 i .idata$6 004077b8 i .idata$6 004075ae i .idata$6 004074a2 i .idata$6 004072c0 i .idata$6 004074fe i .idata$6 004075c0 i .idata$6 00407610 i .idata$6 004073ec i .idata$6 00407324 i .idata$6 00407580 i .idata$6 004075fa i .idata$6 0040751a i .idata$6 0040735e i .idata$6 00407480 i .idata$6 00407790 i .idata$6 004075c8 i .idata$6 00407494 i .idata$6 004074e0 i .idata$6 004074ee i .idata$6 00407674 i .idata$6 0040756c i .idata$6 00407418 i .idata$6 0040750a i .idata$6 00407592 i .idata$6 00407664 i .idata$6 004076e0 i .idata$6 004072dc i .idata$6 0040730c i .idata$6 00407478 i .idata$6 00407604 i .idata$6 004073d2 i .idata$6 00407740 i .idata$6 004075e6 i .idata$6 004075b6 i .idata$6 004073fc i .idata$6 004075d2 i .idata$6 0040745a i .idata$6 00407634 i .idata$6 00407440 i .idata$6 0040754a i .idata$6 004072ac i .idata$6 004076cc i .idata$6 004075f0 i .idata$6 0040733c i .idata$6 0040734a i .idata$6 004074be i .idata$6 004073c0 i .idata$6 004076f8 i .idata$6 00407578 i .idata$6 004075dc i .idata$6 0040739a i .idata$6 00407684 i .idata$6 004073ae i .idata$6 004077ac i .idata$6 00407430 i .idata$6 0040752c i .idata$6 00407558 i .idata$6 00407588 i .idata$6 00407910 i .idata$7 004078a8 i .idata$7 004078a4 i .idata$7 004078f0 i .idata$7 004078e0 i .idata$7 004078e8 i .idata$7 0040791c i .idata$7 004078dc i .idata$7 0040786c i .idata$7 004078b0 i .idata$7 004078c4 i .idata$7 00407858 i .idata$7 00407820 i .idata$7 0040788c i .idata$7 00407934 i .idata$7 00407870 i .idata$7 004078cc i .idata$7 00407924 i .idata$7 00407898 i .idata$7 00407890 i .idata$7 004078a0 i .idata$7 00407834 i .idata$7 00407928 i .idata$7 004078bc i .idata$7 004078ac i .idata$7 004078c8 i .idata$7 00407848 i .idata$7 0040789c i .idata$7 00407804 i .idata$7 004078d4 i .idata$7 004078b8 i .idata$7 004077fc i .idata$7 00407830 i .idata$7 004078ec i .idata$7 004078d8 i .idata$7 00407874 i .idata$7 00407868 i .idata$7 00407888 i .idata$7 00407930 i .idata$7 0040790c i .idata$7 0040782c i .idata$7 00407828 i .idata$7 00407938 i .idata$7 00407850 i .idata$7 004078c0 i .idata$7 004078f4 i .idata$7 00407908 i .idata$7 00407800 i .idata$7 00407894 i .idata$7 0040781c i .idata$7 00407860 i .idata$7 004078e4 i .idata$7 0040792c i .idata$7 0040784c i .idata$7 004077f8 i .idata$7 0040785c i .idata$7 00407918 i .idata$7 00407920 i .idata$7 004078b4 i .idata$7 00407840 i .idata$7 0040793c i .idata$7 00407824 i .idata$7 00407838 i .idata$7 00407914 i .idata$7 00407808 i .idata$7 00407844 i .idata$7 00407854 i .idata$7 00407878 i .idata$7 0040783c i .idata$7 004078d0 i .idata$7 00407904 i .idata$7 00407900 i .idata$7 00407864 i .idata$7 00403030 d .jcr 00403030 d .jcr 00404064 r .rdata 004041ac r .rdata 00404078 r .rdata 004042ac r .rdata 004042a4 r .rdata 00404074 r .rdata 00404000 r .rdata 00404730 r .rdata$zzz 00404370 r .rdata$zzz 004043b0 r .rdata$zzz 004043f0 r .rdata$zzz 00404430 r .rdata$zzz 00404470 r .rdata$zzz 004044b0 r .rdata$zzz 004044f0 r .rdata$zzz 00404530 r .rdata$zzz 004048f0 r .rdata$zzz 00404570 r .rdata$zzz 004045b0 r .rdata$zzz 004045f0 r .rdata$zzz 00404630 r .rdata$zzz 00404670 r .rdata$zzz 004046b0 r .rdata$zzz 00404930 r .rdata$zzz 004046f0 r .rdata$zzz 004048b0 r .rdata$zzz 004042f0 r .rdata$zzz 00404870 r .rdata$zzz 00404770 r .rdata$zzz 004047b0 r .rdata$zzz 004047f0 r .rdata$zzz 004042b0 r .rdata$zzz 00404830 r .rdata$zzz 00404330 r .rdata$zzz 00404970 r .rdata_runtime_pseudo_reloc 004026d8 t .text 004027d0 t .text 00402390 t .text U .text U .text U .text U .text 004026e0 t .text 00402390 t .text 004027c8 t .text 004027d8 t .text 00402140 t .text 00401500 t .text 00402778 t .text U .text 0040270c t .text 004027d8 t .text 00402140 t .text 00402778 t .text 00402780 t .text 00402000 t .text U .text 004026d0 t .text 00402788 t .text 0040270c t .text 004027d8 t .text 00401f60 t .text U .text U .text 00402790 t .text 00401610 t .text 004027a8 t .text 0040270c t .text U .text 004027c0 t .text 00401f50 t .text 0040270c t .text 00402798 t .text 00401b10 t .text U .text U .text 0040270c t .text 00402798 t .text 00401a50 t .text U .text 0040270c t .text 00402714 t .text U .text 00401a40 t .text U .text 00401a40 t .text 00402720 t .text 004018f0 t .text 004027b8 t .text U .text 004018f0 t .text 00402740 t .text 004018f0 t .text 00402748 t .text 004018f0 t .text 00402750 t .text U .text 00401810 t .text 00402758 t .text 00401810 t .text 00402760 t .text 004017f0 t .text 00402768 t .text U .text 004017e0 t .text 004027b0 t .text 00401000 t .text 00401680 t .text U .text 00402770 t .text U .text 00401700 t .text 00401688 t .text 00401690 t .text 00401690 t .text 004016f8 t .text 00401690 t .text U .text 004016f0 t .text U .text 004016e8 t .text 00401698 t .text 004016e0 t .text 004016a0 t .text U .text 004016d8 t .text 004016a8 t .text 004016d0 t .text 004016a8 t .text 004016c8 t .text U .text U .text 004016c0 t .text 004016b0 t .text 004016b8 t .text 004027a0 t .text 004027e0 t .text.startup 004028f0 t .text.startup 00409004 d .tls 00409000 d .tls$AAA 0040901c d .tls$ZZZ 00000000 A .weak.___deregister_frame_info._hmod_libgcc 00000000 A .weak.___register_frame_info._hmod_libgcc 00000000 A .weak.__Jv_RegisterClasses._hmod_libgcc 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 00000001 a @feat.00 004021c0 T ____w64_mingwthr_add_key_dtor 00402250 T ____w64_mingwthr_remove_key_dtor 004026e0 T ___chkstk_ms 0040800c D ___crt_xc_end__ 00408000 D ___crt_xc_start__ 0040801c D ___crt_xi_end__ 0040800c D ___crt_xi_start__ 0040801c D ___crt_xl_start__ 0040802c D ___crt_xp_end__ 0040802c D ___crt_xp_start__ 0040802c D ___crt_xt_end__ 0040802c D ___crt_xt_start__ 00402910 T ___CTOR_LIST__ 004026d0 T ___deregister_frame_info 00402780 T ___dllonexit 00401f90 T ___do_global_ctors 00401f60 T ___do_global_dtors 00402920 T ___DTOR_LIST__ 00401700 t ___dyn_tls_dtor@12 00401750 T ___dyn_tls_init@12 00404074 R ___dyn_tls_init_callback 004050c8 r ___EH_FRAME_BEGIN__ 004058e0 r ___FRAME_END__ 004015b0 T ___gcc_deregister_frame 00401680 T ___gcc_personality_v0 00401500 T ___gcc_register_frame 00402714 T ___getmainargs 00400000 A ___ImageBase 00403030 d ___JCR_END__ 00403030 d ___JCR_LIST__ 00000000 A ___lconv_init 00401fe0 T ___main 00402630 T ___mingw_enum_import_library_names 00402500 T ___mingw_GetSectionCount 004024b0 T ___mingw_GetSectionForAddress 00401000 t ___mingw_invalidParameterHandler 00406064 B ___mingw_oldexcpt_handler 00408014 D ___mingw_pinit 00401a50 T ___mingw_raise_matherr 00401aa0 T ___mingw_setusermatherr 004022f0 T ___mingw_TLScallback 004063ec B ___mingw_winmain_hInstance 004063e8 B ___mingw_winmain_lpCmdLine 00403000 D ___mingw_winmain_nShowCmd 004063c8 b ___mingwthr_cs 004063c4 b ___mingwthr_cs_init 00402140 t ___mingwthr_run_key_dtors.part.0 00403010 D ___native_dllmain_reason 004063fc B ___native_startup_lock 00406400 B ___native_startup_state 0040300c D ___native_vcclrit_reason 004063f8 B ___onexitbegin 004063f4 B ___onexitend 004026d8 T ___register_frame_info 00401b10 t ___report_error 004020b0 T ___report_gsfailure 00404970 A ___RUNTIME_PSEUDO_RELOC_LIST__ 00404988 R ___RUNTIME_PSEUDO_RELOC_LIST_END__ 00403028 D ___security_cookie 0040302c D ___security_cookie_complement 00402000 T ___security_init_cookie 0040270c T ___set_app_type 00402798 T ___setusermatherr 00401610 t ___tcf_0.lto_priv.6 00401620 t ___tcf_0.lto_priv.7 00401650 t ___tcf_1 004017d0 T ___tlregdtor 00409020 D ___tls_end__ 00409000 D ___tls_start__ 00401180 t ___tmainCRTStartup 00408000 D ___xc_a 00408008 D ___xc_z 0040802c d ___xd_a 00408030 d ___xd_z 0040800c D ___xi_a 00408018 D ___xi_z 0040801c D ___xl_a 00408020 D ___xl_c 00408024 D ___xl_d 00408028 D ___xl_z 00402760 T __amsg_exit 00406414 B __bss_end__ 00406000 B __bss_start__ 00402758 T __cexit 00403004 D __charmax 00403018 D __CRT_MT 00402910 T __CTOR_LIST__ 00403034 D __data_end__ 00403000 D __data_start__ 004017f0 T __decode_pointer 00000000 A __dll__ 00000000 A __dll_characteristics__ 00403008 D __dowildcard 00402920 T __DTOR_LIST__ 00401800 T __encode_pointer 0040a000 D __end__ 00000200 A __file_alignment__ 004023d0 T __FindPESection 00402410 T __FindPESectionByName 00402530 T __FindPESectionExec 0040605c B __fmode 00401f50 T __fpreset 00402898 T __fu0___ZSt4cout 00402720 T __get_invalid_parameter_handler 004025a0 T __GetPEImageBase 004027e0 t __GLOBAL__I_65535_0_objects.a_0xd0.3181 004018f0 T __gnu_exception_handler@4 00407014 I __head_lib32_libkernel32_a 00407028 I __head_lib32_libmsvcrt_a 00407000 I __head_libgcc_s_dw2_1_dll 0040703c I __head_libstdc___6_dll 004072ac I __IAT_end__ 00407188 I __IAT_start__ 00400000 A __image_base__ 0040718c I __imp____deregister_frame_info 004071fc I __imp____dllonexit 00407190 I __imp____gcc_personality_v0 00407200 I __imp____getmainargs 00407204 I __imp____initenv 00407208 I __imp____lconv_init 00407194 I __imp____register_frame_info 0040720c I __imp____set_app_type 00407210 I __imp____setusermatherr 00407214 I __imp___acmdln 00407218 I __imp___amsg_exit 0040721c I __imp___cexit 00407220 I __imp___fmode 00403020 D __imp___get_invalid_parameter_handler 00407224 I __imp___initterm 00407228 I __imp___iob 0040722c I __imp___lock 00407230 I __imp___onexit 00403024 D __imp___set_invalid_parameter_handler 00407234 I __imp___unlock 00407188 I __imp___Unwind_Resume 0040726c I __imp___ZNKSt5ctypeIcE13_M_widen_initEv 00407270 I __imp___ZNKSt9basic_iosIcSt11char_traitsIcEE5widenEc 00407274 I __imp___ZNSo3putEc 00407278 I __imp___ZNSo5flushEv 0040727c I __imp___ZNSs4_Rep10_M_destroyERKSaIcE 00407280 I __imp___ZNSs4_Rep10_M_disposeERKSaIcE 00407284 I __imp___ZNSs6appendERKSs 00407288 I __imp___ZNSsC1EPKcRKSaIcE 0040728c I __imp___ZNSsC1ERKSs 00407290 I __imp___ZNSt8ios_base4InitC1Ev 00407294 I __imp___ZNSt8ios_base4InitD1Ev 00407298 I __imp___ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i 0040729c I __imp___ZSt16__throw_bad_castv 004072a0 I __imp___ZSt4cout 004072a0 I __imp___ZSt4cout 004072a4 I __imp___ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 00407238 I __imp__abort 0040723c I __imp__calloc 0040719c I __imp__DeleteCriticalSection@4 004071a0 I __imp__EnterCriticalSection@4 00407240 I __imp__exit 00407244 I __imp__fprintf 00407248 I __imp__free 004071a4 I __imp__FreeLibrary@4 0040724c I __imp__fwrite 004071a8 I __imp__GetCurrentProcess@0 004071ac I __imp__GetCurrentProcessId@0 004071b0 I __imp__GetCurrentThreadId@0 004071b4 I __imp__GetLastError@0 004071b8 I __imp__GetModuleHandleA@4 004071bc I __imp__GetProcAddress@8 004071c0 I __imp__GetStartupInfoA@4 004071c4 I __imp__GetSystemTimeAsFileTime@4 004071c8 I __imp__GetTickCount@0 004071cc I __imp__InitializeCriticalSection@4 004071d0 I __imp__LeaveCriticalSection@4 004071d4 I __imp__LoadLibraryA@4 00407250 I __imp__malloc 00407254 I __imp__memcpy 004071d8 I __imp__QueryPerformanceCounter@4 004071dc I __imp__SetUnhandledExceptionFilter@4 00407258 I __imp__signal 004071e0 I __imp__Sleep@4 0040725c I __imp__strlen 00407260 I __imp__strncmp 004071e4 I __imp__TerminateProcess@8 004071e8 I __imp__TlsGetValue@4 004071ec I __imp__UnhandledExceptionFilter@4 00407264 I __imp__vfprintf 004071f0 I __imp__VirtualProtect@16 004071f4 I __imp__VirtualQuery@12 00402768 T __initterm 004025d0 T __IsNonwritableInCurrentImage U __Jv_RegisterClasses 00407878 I __lib32_libkernel32_a_iname 004078f4 I __lib32_libmsvcrt_a_iname 00000000 A __loader_flags__ 00402778 T __lock 00000000 A __major_image_version__ 00000004 A __major_os_version__ 00000004 A __major_subsystem_version__ 00401ab0 T __matherr 0040301c D __MINGW_INSTALL_DEBUG_MATHERR 00000000 A __minor_image_version__ 00000000 A __minor_os_version__ 00000000 A __minor_subsystem_version__ 00406060 B __newmode 004077ac I __nm___ZSt4cout 00401cb0 T __pei386_runtime_relocator 00404988 R __rt_psrelocs_end 00000018 A __rt_psrelocs_size 00404970 R __rt_psrelocs_start 00404970 A __RUNTIME_PSEUDO_RELOC_LIST__ 00404988 R __RUNTIME_PSEUDO_RELOC_LIST_END__ 00001000 A __section_alignment__ 00402730 T __set_invalid_parameter_handler 00401a40 T __setargv 00001000 A __size_of_heap_commit__ 00100000 A __size_of_heap_reserve__ 00001000 A __size_of_stack_commit__ 00200000 A __size_of_stack_reserve__ 00000003 A __subsystem__ 0040901c D __tls_end 00406050 B __tls_index 00409000 D __tls_start 00409004 D __tls_used 00402788 T __unlock 00401688 T __Unwind_Resume 004023b0 T __ValidateImageBase 00402390 t __ValidateImageBase.part.0 00000000 A __Z9getStringv 00406038 b __ZL7partTwo 004016c8 T __ZNKSt5ctypeIcE13_M_widen_initEv 00000000 A __ZNKSt5ctypeIcE8do_widenEc 00401698 T __ZNKSt9basic_iosIcSt11char_traitsIcEE5widenEc 004016e0 T __ZNSo3putEc 004016d8 T __ZNSo5flushEv 004016a8 T __ZNSs4_Rep10_M_destroyERKSaIcE 00401690 T __ZNSs4_Rep10_M_disposeERKSaIcE 004016f0 T __ZNSs6appendERKSs 004016b0 T __ZNSsC1EPKcRKSaIcE 004016f8 T __ZNSsC1ERKSs 004016b8 T __ZNSt8ios_base4InitC1Ev 004016c0 T __ZNSt8ios_base4InitD1Ev 004016e8 T __ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_i 004016d0 T __ZSt16__throw_bad_castv 004016a0 T __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_ 00406040 b __ZStL8__ioinit 00000000 A __ZStplIcSt11char_traitsIcESaIcEESbIT_T0_T1_ERKS6_S8_ 004027b8 T _abort 0040601c b _argc 00406010 b _argret 00406018 b _argv 004018d0 T _atexit 004027c0 T _calloc 00404194 r _CSWTCH.5 00000000 A _DeleteCriticalSection@4 00000000 A _EnterCriticalSection@4 00406014 b _envp 00402770 T _exit 00401f50 T _fpreset 004027a0 T _fprintf 004027c8 T _free 00000000 A _FreeLibrary@4 004027a8 T _fwrite 00000000 A _GetCurrentProcess@0 00000000 A _GetCurrentProcessId@0 00000000 A _GetCurrentThreadId@0 00000000 A _GetLastError@0 00000000 A _GetModuleHandleA@4 00000000 A _GetProcAddress@8 00000000 A _GetStartupInfoA@4 00000000 A _GetSystemTimeAsFileTime@4 00000000 A _GetTickCount@0 00406080 b _GS_ContextRecord 004042a4 r _GS_ExceptionPointers 00406360 b _GS_ExceptionRecord 004063e4 b _handler 00406004 b _has_cctor 004063f0 B _hmod_libgcc 00000000 A _InitializeCriticalSection@4 00406078 b _initialized 004063c0 b _key_dtor_list 00000000 A _LeaveCriticalSection@4 00407808 I _libgcc_s_dw2_1_dll_iname 0040793c I _libstdc___6_dll_iname 00000000 A _LoadLibraryA@4 00402850 T _main 004014e0 T _mainCRTStartup 0040600c b _mainret 00402740 T _malloc 00406008 b _managedapp 00401b70 t _mark_section_writable 00406070 b _maxSections 00402750 T _memcpy 00406058 B _mingw_app_type 00402720 t _mingw_get_invalid_parameter_handler 00406054 B _mingw_initcharmax 0040604c B _mingw_initltsdrot_force 00406048 B _mingw_initltsdyn_force 00406044 B _mingw_initltssuo_force 00401810 T _mingw_onexit 00408010 D _mingw_pcinit 00408004 D _mingw_pcppinit 00402730 t _mingw_set_invalid_parameter_handler 004017e0 t _my_lconv_init 00406020 b _obj 00403014 d _p.59329 0040603c b _partOne 00000000 A _partOne 00401010 t _pre_c_init 00401130 t _pre_cpp_init 00000000 A _QueryPerformanceCounter@4 004028f0 t _register_frame_ctor 00000000 A _SetUnhandledExceptionFilter@4 00402790 T _signal 00000000 A _Sleep@4 00406000 b _startinfo 00402748 T _strlen 004027d0 T _strncmp 00406068 b _stUserMathErr 00000000 A _TerminateProcess@8 00406074 b _the_secs 00000000 A _TlsGetValue@4 00000000 A _UnhandledExceptionFilter@4 004027b0 T _vfprintf 00000000 A _VirtualProtect@16 00000000 A _VirtualQuery@12 0040606c b _was_init.60615 004014c0 T _WinMainCRTStartup 004071fc i fthunk 0040719c i fthunk 00407078 i hname 004070d8 i hname
Не кажется, что это как-то слишком много для программы, которая ничего не экспортирует в духе DLL?
Заодно запомним размер программы: 52 105 байт.
Теперь несколько изменим CMakeList.txt
add_executable(example2 main.cpp other.cpp) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -flto -s")
Мы добавили флаг -s и изменили имя исполняемого файла. Теперь после сборки программы nm выдаёт следующее:
nm: example2.exe: no symbols
То есть программе для работы не требуется ни одно из 1 001 вышеупомянутого имени!
А что с объёмом? 16 896 байт. То есть мы смогли безболезненно уменьшить размер программы в три раза! И это для двух простых объектных файлов. При усложнении же проекта доля имён от размера исполняемого файла будет ещё больше.
Кстати, вы заметили, что бо́льшую часть символов занимают имена секций? Так вот, это следствие различия форматов объектных (ELF) и исполняемых (PE EXE) файлов при сборке под MinGW, не позволяющего объединить эти имена и использовать их по прямому назначению. Также в таблице имён фигурирует большое количество символов из объектных файлов стандартной библиотеки.

При написании данного ответа использовались следующие версии программ:
CMake 3.4.0, GCC 4.9.2 (i686-posix-dwarf-rev1, Built by MinGW-W64 project), GNU nm (GNU Binutils) 2.24.

понедельник, 4 февраля 2019 г.

C++: Undefined reference при линковке теста с либой

Вот исходник тесты #include #include using namespace RFw;
int main() { Array _a_;
_a_.resize(5);
_a_[2] = 'b'; _a_[3] = 'a';
printf("%c%c
", *(_a_.provideElement(2)), *(_a_.provideElement(3)));
return 0; } Так компилю: c++ test.cpp -o test -std=c++11 -Isrc-core/ -Lbin/ -lcore Вывод: /tmp/test-k6aFM8.o: In function `main': test.cpp.text+0x27): undefined reference to `RFw::Array::Array(unsigned int, int*)' test.cpp.text+0x3a): undefined reference to `RFw::Array::resize(unsigned int)' test.cpp:(.text+0x52): undefined reference to `RFw::Array::operator[](unsigned int)' test.cpp:(.text+0x76): undefined reference to `RFw::Array::operator[](unsigned int)' test.cpp:(.text+0x9a): undefined reference to `RFw::Array::provideElement(unsigned int)' test.cpp:(.text+0xbd): undefined reference to `RFw::Array::provideElement(unsigned int)' test.cpp:(.text+0x101): undefined reference to `RFw::Array::~Array()' test.cpp:(.text+0x11b): undefined reference to `RFw::Array::~Array()' clang: error: linker command failed with exit code 1 (use -v to see invocation) PS Array взят из Array.hpp который инклюдится в common.hpp Array.hpp: /** * src-core/Array.hpp */ #ifndef _ARRAY_HPP_ #define _ARRAY_HPP_
#include "util.hpp" #include "Object.hpp" #include "arrayExceptions.hpp"
namespace RFw { template class Array : public Object { public: Array(intnum _length = 0, TValue* _array = nullptr); virtual ~Array();
void addToTop(const TValue _element) throw(ArrayOverflowException); void addToEnd(const TValue _element) throw(ArrayOverflowException); void clone(const intnum _length, const TValue* _array);
TValue* provideElement(const intnum _index) throw(IndexOutOfRangeException); const TValue* provideElement(const intnum _index) const throw(IndexOutOfRangeException);
TValue& operator[](const intnum _index) throw(IndexOutOfRangeException); const TValue& operator[](const intnum _index) const throw(IndexOutOfRangeException);
void resize(const intnum _newLentgh);
const Array getClone() const; const intnum getLength() const; const TValue* getArray() const; private: intnum length__; TValue* array__; }; }
#endif // _ARRAY_HPP_


Ответ

С шаблонами вы должны помещать реализацию методов в header.
В вашем случае пишите так:
template class Array : public Object { public: Array(intnum _length = 0, TValue* _array = nullptr) : length__(_length), array__(new TValue[_length]) { // остаток имплементации } virtual ~Array() { delete[] array__; } // и так далее };
Если вы вынесете реализацию методов в .cpp-файл, компилятор не будет знать, какие инстанциации шаблона ему нужно компилировать. Это ограничение модели компиляции языка C++. Sorry for this.

Небольшое объяснение. В C++ шаблон не есть класс, это лишь «описание», по которому при подстановке шаблонных аргументов генерируется реальный класс. Никакого объектного кода шаблон сам по себе не производит.
Когда компилятор компилирует C++-файл с кодом, использующим шаблон, он видит, с каким шаблонным аргументом используется этот шаблон. Но когда он компилирует C++-файл с реализацией шаблонных методов, он не знает, с какими аргументами инстанциировался шаблон в других файлах, ведь каждый C++-файл компилируется по отдельности!
Поэтому решением является положить реализацию внутрь шаблонного класса. При этом компилятор в той точке, где он видит инстанциацию шаблона, видит весь его код, и может скомпилировать все методы класса.
(Существует ещё уродливый костыль с указанием в C++-файле точного списка инстанциаций шаблона, который настолько ужасен, что я не хочу о нём и говорить. Аналогом этому было бы около каждой функции указывать заранее список всех аргументов, с которым функция будет вызвана в программе.)

среда, 5 декабря 2018 г.

Изменить сегмент в ld

По умолчанию ld, как я понял, считает, что в %ds находится 0 и соответственно компонует программу на языке C с этим значением. Как его изменить в настройках компоновщика, чтобы при изменении %ds на другое значение в программе (например, 0x07c0), она работала корректно?
На всякий случай уточню, что речь идёт о написании программы наподобие загрузчика.


Ответ

Как я понял, напрямую задать %ds нельзя, но зато для секции .data можно указать VMA, что расшифровывается, как Virtual Memory Address. После этого, компоновщик будет загружать секцию по LMA (Load Memory Address), но адреса переменных, находящихся в этой секции, при обращении к этим переменным из программы, будут начинаться с VMA, а не с LMA.
Рассмотрим такой пример: в %ds устанавливается в коде значение 0x07c0, секция .text загружается по адресу 0x7c00, .data находится сразу после .text. Тогда необходимо установить VMA равным размеру секции .text. После этого, например, переменная, находящаяся в самом начале секции .data, при обращении к ней из кода программы, будет иметь адрес %ds*16+Размер секции .text=0x7c00+Размер секции .text. Это соответствует фактическому расположению переменной. Полный код скрипта компоновщика:
ENTRY(main); SECTIONS { . = 0x7C00; /*установлен только LMA, VMA такой же */ .text : AT(0x7C00) { _text = .; *(.text*); _text_end = .; } /*VMA=SIZEOF(.text) LMA=ADDR (.text) + SIZEOF (.text)*/ .data (SIZEOF(.text)) : AT(ADDR (.text) + SIZEOF (.text)) { _data = .; *(.bss); *(.bss*); *(.data); *(.rodata*); *(COMMON) _data_end = .; } .sig : AT(0x7DFE) { SHORT(0xaa55); } /DISCARD/ : { *(.note*); *(.iplt*); *(.igot*); *(.rel*); *(.comment); *(.eh_frame); } }
Подробнее про LMA и VMA можно почитать по этой ссылке https://sourceware.org/binutils/docs/ld/Output-Section-LMA.html