Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 22.11.04 16:57
Оценка:
Всем доброго времени суток!

Вот возник вопрос: 1. При сборке линкуются все функции или только те которые используются?
2. А если только те, которые используются, то как линкер умудряется оторвать их тело от всего остального контекста?
Меня даже больше интересуют ответ на второй вопрос...
Re: Линкер
От: BlackHeretic Израиль  
Дата: 22.11.04 17:34
Оценка: -2
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Всем доброго времени суток!


ATP>Вот возник вопрос: 1. При сборке линкуются все функции или только те которые используются?

ATP>2. А если только те, которые используются, то как линкер умудряется оторвать их тело от всего остального контекста?
ATP>Меня даже больше интересуют ответ на второй вопрос...

1. Все.
2. см. отв. 1
ICQ 156156278
Re[2]: Линкер
От: Sergey J. A. Беларусь  
Дата: 22.11.04 18:01
Оценка:
Здравствуйте, BlackHeretic, Вы писали:

ATP>>Всем доброго времени суток!


ATP>>Вот возник вопрос: 1. При сборке линкуются все функции или только те которые используются?

ATP>>2. А если только те, которые используются, то как линкер умудряется оторвать их тело от всего остального контекста?
ATP>>Меня даже больше интересуют ответ на второй вопрос...

BH>1. Все.

BH>2. см. отв. 1

Интересно из каких соображений это выдумано ?
В действительности стандарт C++ это не оговаривает. Поэтому каждый производитель сам решает что и как в данной ситуации делать.
Майкрософтовский линкер (по крайней мере от VC 6.0 и далее) выбрасывает не использующиеся ф-ии. Более того (впрочем, возможно это делает компилятор) он может объединять одинаковые ф-ии. Например код vector<int> и vector<long> ничем не различается (32 бинтая x86 платформа), поэтому он объединяется в одну ф-ию (проверено).
Как выбрасывает ? Это доподлинно мне не извесно.
Однако никаких трудностей я не вижу...
Допустим: Каждый кусок кода помечен именем. Это может быть ф-ия, глобальная переменная. Также есть таблица использования — какой блок что использует. Линкер находит куски, которые не используются другими другими и не включает их в результирующий файл. Поскольку в разных call и jmp используется не абсолютный адрес, а относительный — их править не нужно. А те куски, что нужно прописаны в другой таблице — релокаций. В итоге получаем довольно худой файл.
Я — свихнувшееся сознание Джо.
Re[3]: Линкер
От: rus blood Россия  
Дата: 22.11.04 18:08
Оценка:
Здравствуйте, Sergey J. A., Вы писали:

SJA>Допустим: Каждый кусок кода помечен именем. Это может быть ф-ия, глобальная переменная. Также есть таблица использования — какой блок что использует. Линкер находит куски, которые не используются другими другими и не включает их в результирующий файл. Поскольку в разных call и jmp используется не абсолютный адрес, а относительный — их править не нужно. А те куски, что нужно прописаны в другой таблице — релокаций. В итоге получаем довольно худой файл.


Сборка мусора по периметру. GarbageCollector.
Имею скафандр — готов путешествовать!
Re[4]: Линкер
От: Sergey J. A. Беларусь  
Дата: 22.11.04 18:17
Оценка:
Здравствуйте, rus blood, Вы писали:

SJA>>Допустим: Каждый кусок кода помечен именем. Это может быть ф-ия, глобальная переменная. Также есть таблица использования — какой блок что использует. Линкер находит куски, которые не используются другими другими и не включает их в результирующий файл. Поскольку в разных call и jmp используется не абсолютный адрес, а относительный — их править не нужно. А те куски, что нужно прописаны в другой таблице — релокаций. В итоге получаем довольно худой файл.


RB>Сборка мусора по периметру. GarbageCollector.

22.
Я — свихнувшееся сознание Джо.
Re[3]: Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 22.11.04 19:24
Оценка:
Здравствуйте, Sergey J. A., Вы писали:

SJA>Здравствуйте, BlackHeretic, Вы писали:


ATP>>>Всем доброго времени суток!


ATP>>>Вот возник вопрос: 1. При сборке линкуются все функции или только те которые используются?

ATP>>>2. А если только те, которые используются, то как линкер умудряется оторвать их тело от всего остального контекста?
ATP>>>Меня даже больше интересуют ответ на второй вопрос...

BH>>1. Все.

BH>>2. см. отв. 1

SJA>Интересно из каких соображений это выдумано ?


Во первых, BlackHeretic имеет совершенно отличную точку зрения от вашей


SJA>В действительности стандарт C++ это не оговаривает. Поэтому каждый производитель сам решает что и как в данной ситуации делать.

SJA>Майкрософтовский линкер (по крайней мере от VC 6.0 и далее) выбрасывает не использующиеся ф-ии.

Выбрасывает из исходного кода, во время компиляции — да, а из линкуемой либы — вопрос?

Более того (впрочем, возможно это делает компилятор) он может объединять одинаковые ф-ии. Например код vector<int> и vector<long> ничем не различается (32 бинтая x86 платформа), поэтому он объединяется в одну ф-ию (проверено).

Все, что выбрасывается на стадии компиляции, меня не интересовало, итак понятно.

SJA>Как выбрасывает ? Это доподлинно мне не извесно.


Вот это собственно и был мой вопрос.

SJA>Однако никаких трудностей я не вижу...


А я как раз вижу, причем на мой взгляд неразрешимые.

SJA>Допустим: Каждый кусок кода помечен именем. Это может быть ф-ия, глобальная переменная. Также есть таблица использования — какой блок что использует. Линкер находит куски, которые не используются другими другими и не включает их в результирующий файл.


Интересно как же он это делает, ведь функция может вызывать другие, те в свою очередь другие, и т.д. На мой взгляд разобраться в этой иерархии линкеру (не компилятору) будет очень сложно, если ввобще невозможно. И потом кто сказал, что либа вообще написана на С++, она вообще может быть написана на ассемблере, где вообще граница между функциями стирается.

SJA> Поскольку в разных call и jmp используется не абсолютный адрес, а относительный — их править не нужно. А те куски, что нужно прописаны в другой таблице — релокаций. В итоге получаем довольно худой файл.


Вот как раз с таким подходом, на их править как раз и нужно. Пример:

есть либа:

1. Глобальная таблица данных
2. Функция 1
3. Функция 2
4. Функция 3

Предположим все три фукции используют глобальные данные и что мы используем только функцию 2 из либы.
Получается, что мы должны выкинуть функции 1 и 3. А может и не должны, т.к как они могут вызываться из функции в функции которая вызывается в Функции 2? А если должны выкинуть, то смещения на глобальные данные изменится, и относительные адреса не помогут. Так как же линкер поступит в этом случае?

Есть ли действительно компетентные специалисты в данном вопросе, которые могли бы помоч разобраться мне в данном вопросе?
Re: Линкер
От: aka50 Россия  
Дата: 23.11.04 07:23
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Всем доброго времени суток!


ATP>Вот возник вопрос: 1. При сборке линкуются все функции или только те которые используются?

ATP>2. А если только те, которые используются, то как линкер умудряется оторвать их тело от всего остального контекста?
ATP>Меня даже больше интересуют ответ на второй вопрос...


1. Линкуется единица трансляции из библиотеки (во всяком случае gcc, в win32 скорее всего что-то похожее), т.е. имеем:

someunit.cpp
someunit2.cpp

Дык вот, если будет использоваться функция из someunit.cpp, то весь объектный someunit.o код попадет итогововый бинарь.
И если при этом из someunit2.cpp ничего использоваться не будет, то он никуда не попадет.

2. Не уверен 100%, руки еще не дошли проверить, но это возможно с флагом global optimization. Тогда
после сборки, стоится xref таблица, в которой оптимизатор ищет неиспользуемые функции и выкидывает их.
Правда если функция помечена как export, ее он точно никуда не выкенет.
Re[4]: Линкер
От: Sergey J. A. Беларусь  
Дата: 23.11.04 08:27
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Во первых, BlackHeretic имеет совершенно отличную точку зрения от вашей


Вот именно. Причём ничем не подтвердмл своё высказывание.

ATP>Вот это собственно и был мой вопрос.

Ну я не пишу компиляторы. У меня есть только предположения, которые подтверждаются практикой. Больше ничем не могу помочь.

SJA>>Однако никаких трудностей я не вижу...

ATP>А я как раз вижу, причем на мой взгляд неразрешимые.
А я всё же не вижу

ATP>Есть ли действительно компетентные специалисты в данном вопросе, которые могли бы помоч разобраться мне в данном вопросе?

Действительно компетентные работают над улучшением компиляторв и не лазают по форумам. Послушайте хотя бы просто компетентного.

Итак. Исследования в лабораторных условиях.
Дано: родной компилятор и линкер от MS Visual Studio 6.0, Far manager + Colorer и немного любопытства.

1. Выбрасывет ли линкер не нужные ф-ии из lib ?
Итак пишем небольшую либку с ф-ией:
void f_lib()
{
    volatile int a = 0;
    if(a)
    {
        __asm
        {
            int 3
            int 2
        }
    }
};

Компилируем в релизе. Берём Far manager, ищем коды CC CD 02 — это коды нашей ассемблерной вставки. Находми. Значит ф-ия присутствует в либке.

Создаём проект, в нём импортируем ф-ию, добавляем в проект либку, добиваемся успешной компиляции (release). Код примерно такой:
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
{
    __asm{int 3}
    f_lib();
    return 0;
}

Компилируем. Берём Far manager, ищем коды CC CD 02 — (коды нашей ассемблерной вставки). Находми. Значит ф-ия присутствует в екзешнике.
Замечательно. Коментируем вызов ф-ии f_lib(); теперь она не нужна и линкер может попытаться выбровить её.
Опять берём Far manager, ищем коды CC CD 02 — не находим. Вывод ?
Вывод: Линкер выбрасывает ненужные ф-ии из либок.

2. Выбрасывет ли линкер ненужные ф-ии из obj ?
Проект:
File2.cpp: здесь иы положим ф-ию с вставкой CC CD 02
void f2()
{
    volatile int a = 0;
    if(a)
    {
        __asm
        {
            int 3
            int 2
        }
    }
}


File1.cpp: здесь иы положим ф-ию с вставкой CC CD 01 и используем обе.
void f2();

void f1()
{
    volatile int a = 0;
    if(a)
    {
        __asm
        {
            int 3
            int 1
        }
    }
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
{
    __asm{int 3}
    f1();
    f2();
    return 0;
}

Компилируем, проверяем. Обе вставки на месте. Коментируем по очереди обе ф-ии, проверяем — вставки исчезают.
Вывод:
Линкер выбрасывает ненужные ф-ии из объектных файлов.
Пометка: функцию f1() не может выбросить компилятор, т.е. она не статическая и может использоваться в другом объектном файле. Компилятор не может делать предаоложения и засовывает f1 в obj в любом случае.

3. Объединяет ли линкер похожие ф-ии ?
Проект:
File2.cpp: здесь иы положим ф-ию с вставкой CC CD 02
void f2()
{
    std::vector<int> v;
    v.push_back(100);
    volatile a = v.size();
}


File1.cpp: здесь иы положим ф-ию с вставкой CC CD 01 и используем обе.
void f2();

void f1()
{
    std::vector<long> v;
    v.push_back(100);
    volatile a = v.size();
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
{
    __asm{int 3}
    f1();
    f2();
    return 0;
}

Запускаем под отладчиком (release версия !), проверяем и видим, что адреса std::vector<int>::push_back и std::vector<long>::push_back совмадают.

Вывод:
Линкер может находить одинаковые куски кода и объединять их.

Теоретические изыскания:
Как это делает линкер ?

Шьёрт. Писал, писал. Не сохранил. А я(а)нус упал.....
Ладно. Буду краток.
Компилятор составляет таблица в которой прописано что где исиспользовано. Допустим WimMain использует f(), f() использует cool_func() ...
Линкер начинает с ф-ии указанной как entry. Ложит её. Смотрит, что она вызывает. Ложит их. И т.д. В результате все нужные ф-ии попадают в экзешник. (+ возможно есть какие-то сущности безусловно попадающие в результат). С иерархией использования думаю понятно.

Адреса.
При компиляции в объектный файл не ложаться. Вместо этого в таблице (вероятнее всего это та же таблица использования) помечается: ф-ия WinMain по смещению +10h использует отностельный адрес сущности f().
После того, как линкер соберёт все нужные процедуры он пробегается по таблице и прописывает по нужным смещениям нужные адреса. Т.е. пропишет в WinMain по мещению +10h реальный адрес f(). Причём линкеру в принципе не интересно что такое f() — ф-ия или это глобальная переменная: он знает адрес f() и знает куда его нужно вписать.

Насчёт ассемблера.
Формат объектного файла одинаков для ассемблера и С++. Если писать по определённым правилам, думаю можно добиться авбрасывания ненужных ф-ий и из асм-либки. Правила примерно такие (я только предпологаю — проверять лень):
Каждая сущность должна распологаться в отдельном сегменте. Каждая сущность должна быть PUBLIC.
Думаю в этом случае линкер будет иметь возможность покилять ненужные секции (на которые нет ссылок) и сделать релокацию и слияние оставшихся.
Вот допустим как это делает VC 6.0:
Из
#include "stdafx.h"

volatile int a = 10;

void f()
{
    a = 1;
};

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
{
    f();
    return 0;
}


Получаем:
PUBLIC    ?a@@3HC                        ; Публичное имя переменной a
_DATA    SEGMENT                            ; сегмент с переменной
?a@@3HC    DD    0aH                    ; значние
_DATA    ENDS

PUBLIC    ?f@@YAXXZ                    ; Имя ф-ии f
;    COMDAT ?f@@YAXXZ
_TEXT    SEGMENT
?f@@YAXXZ PROC NEAR                    ; Тело ф-ии f, COMDAT
    mov    DWORD PTR ?a@@3HC, 1            ; a
    ret    0
?f@@YAXXZ ENDP                        ; f
_TEXT    ENDS

PUBLIC    _WinMain@16
;    COMDAT _WinMain@16
_TEXT    SEGMENT
_WinMain@16 PROC NEAR                    ; COMDAT
    call    ?f@@YAXXZ                ; f
    xor    eax, eax
    ret    16                    ; 00000010H
_WinMain@16 ENDP
_TEXT    ENDS

Как видим каждая сущность в своём сегменте.
Я — свихнувшееся сознание Джо.
Re[2]: Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 23.11.04 08:35
Оценка:
Здравствуйте, aka50, Вы писали:

A>Здравствуйте, AcidTheProgrammer, Вы писали:


ATP>>Всем доброго времени суток!


ATP>>Вот возник вопрос: 1. При сборке линкуются все функции или только те которые используются?

ATP>>2. А если только те, которые используются, то как линкер умудряется оторвать их тело от всего остального контекста?
ATP>>Меня даже больше интересуют ответ на второй вопрос...


A>1. Линкуется единица трансляции из библиотеки (во всяком случае gcc, в win32 скорее всего что-то похожее), т.е. имеем:


A>someunit.cpp

A>someunit2.cpp

A>Дык вот, если будет использоваться функция из someunit.cpp, то весь объектный someunit.o код попадет итогововый бинарь.

A>И если при этом из someunit2.cpp ничего использоваться не будет, то он никуда не попадет.

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

A>2. Не уверен 100%, руки еще не дошли проверить, но это возможно с флагом global optimization. Тогда

A>после сборки, стоится xref таблица, в которой оптимизатор ищет неиспользуемые функции и выкидывает их.
A>Правда если функция помечена как export, ее он точно никуда не выкенет.

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

Так всетаки вопрос: Викидывает ли линкер из уже откомпилированной библиотеки или oбъектника (.lib, .a, .obj, .o) отдельные функции или он может оперировать только единицами трансляции?
Re[2]: Линкер
От: Sergey J. A. Беларусь  
Дата: 23.11.04 08:56
Оценка:
Здравствуйте, aka50, Вы писали:

A>Дык вот, если будет использоваться функция из someunit.cpp, то весь объектный someunit.o код попадет итогововый бинарь.

Как показали исследования VC6.0 не ложит весь объектник, а только то что нужно.

A>2. Не уверен 100%, руки еще не дошли проверить, но это возможно с флагом global optimization. Тогда

A>после сборки, стоится xref таблица, в которой оптимизатор ищет неиспользуемые функции и выкидывает их.
A>Правда если функция помечена как export, ее он точно никуда не выкенет.

Немного не так. Незнаю как по стандарту, но для VC6.0 любая не static ф-ия является внешней. Т.е. проще говоря если в одном файле написать ф-ию f():
void f()
{
};

то в другом файле можно написать:

void f();

void f2
{
    f();
};

И всё сработает. Что говорит о том, что f по умолчанию внешняя. Поэтому компилятор может выбрасывать только static ф-ии, которые не видны извне.
Скорее вего по стандарту это правильно, ибо зачем иначе этот модификатор static для ф-ии ?
Я — свихнувшееся сознание Джо.
Re[5]: Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 23.11.04 09:04
Оценка: -2
Здравствуйте, Sergey J. A., Вы писали:

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

Начинаем попорядку:

SJA>Итак. Исследования в лабораторных условиях.

SJA>Дано: родной компилятор и линкер от MS Visual Studio 6.0, Far manager + Colorer и немного любопытства.


SJA>1. Выбрасывет ли линкер не нужные ф-ии из lib ?

SJA>Итак пишем небольшую либку с ф-ией:
SJA>
SJA>void f_lib()
SJA>{
SJA>    volatile int a = 0;
SJA>    if(a)
SJA>    {
SJA>        __asm
SJA>        {
SJA>            int 3
SJA>            int 2
SJA>        }
SJA>    }
SJA>};
SJA>

SJA>Компилируем в релизе. Берём Far manager, ищем коды CC CD 02 — это коды нашей ассемблерной вставки. Находми. Значит ф-ия присутствует в либке.

Конечно — кудаж она денется

SJA>Создаём проект, в нём импортируем ф-ию, добавляем в проект либку, добиваемся успешной компиляции (release). Код примерно такой:

SJA>
SJA>int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
SJA>{
SJA>    __asm{int 3}
SJA>    f_lib();
SJA>    return 0;
SJA>}
SJA>

SJA>Компилируем. Берём Far manager, ищем коды CC CD 02 — (коды нашей ассемблерной вставки). Находми. Значит ф-ия присутствует в екзешнике.

А теперь внимание!

SJA>Замечательно. Коментируем вызов ф-ии f_lib(); теперь она не нужна и линкер может попытаться выбровить её.

SJA>Опять берём Far manager, ищем коды CC CD 02 — не находим. Вывод ?
SJA>Вывод: Линкер выбрасывает ненужные ф-ии из либок.

Непонимаю, как на очснове данного опыта можно смделать такой поспешный вывод?!
Да — линкер викинул либу, т.к неодна из ее функций не используется. И данный случай самый трививльный — он ниочем не говорит.
Вот если бы вы сделали 20-ток функций, и вызывали бы их все, а потом закоментировали одну, то увидели бы, что все функции в exeшнике на месте.

SJA>2. Выбрасывет ли линкер ненужные ф-ии из obj ?

SJA>Проект:
SJA>File2.cpp: здесь иы положим ф-ию с вставкой CC CD 02
SJA>
SJA>void f2()
SJA>{
SJA>    volatile int a = 0;
SJA>    if(a)
SJA>    {
SJA>        __asm
SJA>        {
SJA>            int 3
SJA>            int 2
SJA>        }
SJA>    }
SJA>}
SJA>


SJA>File1.cpp: здесь иы положим ф-ию с вставкой CC CD 01 и используем обе.

SJA>
SJA>void f2();

SJA>void f1()
SJA>{
SJA>    volatile int a = 0;
SJA>    if(a)
SJA>    {
SJA>        __asm
SJA>        {
SJA>            int 3
SJA>            int 1
SJA>        }
SJA>    }
SJA>}

SJA>int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
SJA>{
SJA>    __asm{int 3}
SJA>    f1();
SJA>    f2();
SJA>    return 0;
SJA>}
SJA>

SJA>Компилируем, проверяем. Обе вставки на месте. Коментируем по очереди обе ф-ии, проверяем — вставки исчезают.
SJA>Вывод:
SJA>Линкер выбрасывает ненужные ф-ии из объектных файлов.

А вот тут у человека полная каша в голове, т.к он путает ликер и компилятор. Компилятор, выкидывает функции — это понято и так, и естественно не пишет в объектник неиспользуемых функций. Теперь представте, что линкер отделная программа, и ей на вход приходит объектник, в котором есть функции составлящие либу. Предположим что вызывается из все только три. И как по вашему линкер (не компилятор) должен понять какие из них дейсвительно нужны, а какие нет?

Данный опыть совершенно не в тему....

SJA>Пометка: функцию f1() не может выбросить компилятор, т.е. она не статическая и может использоваться в другом объектном файле. Компилятор не может делать предаоложения и засовывает f1 в obj в любом случае.


SJA>3. Объединяет ли линкер похожие ф-ии ?

SJA>Проект:
SJA>File2.cpp: здесь иы положим ф-ию с вставкой CC CD 02
SJA>
SJA>void f2()
SJA>{
SJA>    std::vector<int> v;
SJA>    v.push_back(100);
SJA>    volatile a = v.size();
SJA>}
SJA>


SJA>File1.cpp: здесь иы положим ф-ию с вставкой CC CD 01 и используем обе.

SJA>
SJA>void f2();

SJA>void f1()
SJA>{
SJA>    std::vector<long> v;
SJA>    v.push_back(100);
SJA>    volatile a = v.size();
SJA>}

SJA>int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
SJA>{
SJA>    __asm{int 3}
SJA>    f1();
SJA>    f2();
SJA>    return 0;
SJA>}
SJA>

SJA>Запускаем под отладчиком (release версия !), проверяем и видим, что адреса std::vector<int>::push_back и std::vector<long>::push_back совмадают.

SJA>Вывод:

SJA>Линкер может находить одинаковые куски кода и объединять их.

Опять полная каша в голове, пулное непонимание вопроса. ЛИНКЕРРРРР — причем тут компилятор. То что вы описали делает компилятор....

SJA>Теоретические изыскания:

SJA>Как это делает линкер ?

SJA>Шьёрт. Писал, писал. Не сохранил. А я(а)нус упал.....

SJA>Ладно. Буду краток.
SJA>Компилятор составляет таблица в которой прописано что где исиспользовано. Допустим WimMain использует f(), f() использует cool_func() ...
SJA>Линкер начинает с ф-ии указанной как entry. Ложит её. Смотрит, что она вызывает. Ложит их. И т.д. В результате все нужные ф-ии попадают в экзешник. (+ возможно есть какие-то сущности безусловно попадающие в результат). С иерархией использования думаю понятно.

SJA>Адреса.

SJA>При компиляции в объектный файл не ложаться. Вместо этого в таблице (вероятнее всего это та же таблица использования) помечается: ф-ия WinMain по смещению +10h использует отностельный адрес сущности f().
SJA>После того, как линкер соберёт все нужные процедуры он пробегается по таблице и прописывает по нужным смещениям нужные адреса. Т.е. пропишет в WinMain по мещению +10h реальный адрес f(). Причём линкеру в принципе не интересно что такое f() — ф-ия или это глобальная переменная: он знает адрес f() и знает куда его нужно вписать.

Тут далше просто какие-то рассуждения, как могло быть то, чего на самом деле нет.... или есть, но это совсем не потому, почему вы думаете. И делает это все не линкер.

SJA>Насчёт ассемблера.

SJA>Формат объектного файла одинаков для ассемблера и С++. Если писать по определённым правилам, думаю можно добиться авбрасывания ненужных ф-ий и из асм-либки. Правила примерно такие (я только предпологаю — проверять лень):
SJA>Каждая сущность должна распологаться в отдельном сегменте. Каждая сущность должна быть PUBLIC.
SJA>Думаю в этом случае линкер будет иметь возможность покилять ненужные секции (на которые нет ссылок) и сделать релокацию и слияние оставшихся.

Вы хоть раз писали на ассемблере?

SJA>Вот допустим как это делает VC 6.0:

SJA>Из
SJA>
SJA>#include "stdafx.h"

SJA>volatile int a = 10;

SJA>void f()
SJA>{
SJA>    a = 1;
SJA>};

SJA>int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR     lpCmdLine, int       nCmdShow)
SJA>{
SJA>    f();
SJA>    return 0;
SJA>}
SJA>


SJA>Получаем:

SJA>
SJA>PUBLIC    ?a@@3HC                        ; Публичное имя переменной a
SJA>_DATA    SEGMENT                            ; сегмент с переменной
SJA>?a@@3HC    DD    0aH                    ; значние
SJA>_DATA    ENDS

SJA>PUBLIC    ?f@@YAXXZ                    ; Имя ф-ии f
SJA>;    COMDAT ?f@@YAXXZ
SJA>_TEXT    SEGMENT
SJA>?f@@YAXXZ PROC NEAR                    ; Тело ф-ии f, COMDAT
SJA>    mov    DWORD PTR ?a@@3HC, 1            ; a
SJA>    ret    0
SJA>?f@@YAXXZ ENDP                        ; f
SJA>_TEXT    ENDS

SJA>PUBLIC    _WinMain@16
SJA>;    COMDAT _WinMain@16
SJA>_TEXT    SEGMENT
SJA>_WinMain@16 PROC NEAR                    ; COMDAT
SJA>    call    ?f@@YAXXZ                ; f
SJA>    xor    eax, eax
SJA>    ret    16                    ; 00000010H
SJA>_WinMain@16 ENDP
SJA>_TEXT    ENDS
SJA>

SJA>Как видим каждая сущность в своём сегменте.

Во пример который разбивает впух и прах ваши рассуждения насчет ассеблера:


; ...... тут хренова туча кода
....
....
....
....
call eax


И какую я функцию интересно вызвал? Этого линкеру никогда не понять.

Поэтому вывод такой, ввсе что вы описали — это антинаучно и вообще полное непонимание, того что просходит в процессе компиляции.

Так что вопрос по прежнему остается открытым.
Re[4]: Линкер
От: BlackHeretic Израиль  
Дата: 23.11.04 09:16
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

Вот уж не думал что это вызовет такое обсуждение...
В общем правило линковки с либой такое:
Если имеется хотя бы что-то (имя функции, имя переменной) что юзается в проге — либа линкуется полностью. Если нет — выкидывается полностью (линкер обычно кидает предупреждение об этом) — хотя это как правило по умолчанию — можно сказать линкеру линковать либу в любом случае.
Полная линковка обусловлена тем, что практически невозможно быть увереным в вызове/невызове той или иной функции (кроме прямых вызовов есть еще и всякие косвенные, да такие косвенные — что без пол литры никак)
ICQ 156156278
Re[5]: Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 23.11.04 09:23
Оценка:
Здравствуйте, BlackHeretic, Вы писали:

BH>Здравствуйте, AcidTheProgrammer, Вы писали:


BH>Вот уж не думал что это вызовет такое обсуждение...

BH>В общем правило линковки с либой такое:
BH>Если имеется хотя бы что-то (имя функции, имя переменной) что юзается в проге — либа линкуется полностью. Если нет — выкидывается полностью (линкер обычно кидает предупреждение об этом) — хотя это как правило по умолчанию — можно сказать линкеру линковать либу в любом случае.
BH>Полная линковка обусловлена тем, что практически невозможно быть увереным в вызове/невызове той или иной функции (кроме прямых вызовов есть еще и всякие косвенные, да такие косвенные — что без пол литры никак)

Вы правы, но только в лучае, если ваша либа реализована как один файл, т.е. линкуется в один объектник. Тут точно линкер никак не опредлит что нужно, а что нет, и вставит все.

Но сдается мне, что ака50 прав: этому есть косвенное подтверждение, т.к стандартные библиотеки С реализованы так: каждая функция в отдельном файле. Поэтому при линковке стандартых либ, линкуются только одтдельные функции, т.к каждая находится в отдельном объектнике.

Только вот хочется узнать это точно — на все 100.
Re[6]: Линкер
От: BlackHeretic Израиль  
Дата: 23.11.04 09:27
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Здравствуйте, BlackHeretic, Вы писали:


BH>>Здравствуйте, AcidTheProgrammer, Вы писали:


BH>>Вот уж не думал что это вызовет такое обсуждение...

BH>>В общем правило линковки с либой такое:
BH>>Если имеется хотя бы что-то (имя функции, имя переменной) что юзается в проге — либа линкуется полностью. Если нет — выкидывается полностью (линкер обычно кидает предупреждение об этом) — хотя это как правило по умолчанию — можно сказать линкеру линковать либу в любом случае.
BH>>Полная линковка обусловлена тем, что практически невозможно быть увереным в вызове/невызове той или иной функции (кроме прямых вызовов есть еще и всякие косвенные, да такие косвенные — что без пол литры никак)

ATP>Вы правы, но только в лучае, если ваша либа реализована как один файл, т.е. линкуется в один объектник. Тут точно линкер никак не опредлит что нужно, а что нет, и вставит все.


ATP>Но сдается мне, что ака50 прав: этому есть косвенное подтверждение, т.к стандартные библиотеки С реализованы так: каждая функция в отдельном файле. Поэтому при линковке стандартых либ, линкуются только одтдельные функции, т.к каждая находится в отдельном объектнике.


ATP>Только вот хочется узнать это точно — на все 100.


Про объектники честно говоря не знаю. Но логично предположить что так оно и есть (в случае если каждая функция реализована отдельным объектником).
ICQ 156156278
Re[6]: Линкер
От: Sergey J. A. Беларусь  
Дата: 23.11.04 09:39
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Непонимаю, как на очснове данного опыта можно смделать такой поспешный вывод?!

ATP>Да — линкер викинул либу, т.к неодна из ее функций не используется. И данный случай самый трививльный — он ниочем не говорит.
ATP>Вот если бы вы сделали 20-ток функций, и вызывали бы их все, а потом закоментировали одну, то увидели бы, что все функции в exeшнике на месте.

Согласен. Недоделал. Однако только что попробовал вставить 2 ф-ии в либку (в один файл). Затем использовал обе и каждую по очереди. Ответственно заявляю — ВЫБРАСЫВАЕТ ! Прежде чем ответить, потрудитесь хотя бы проверить это.

SJA>>Линкер выбрасывает ненужные ф-ии из объектных файлов.


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

Боюсь тут ты не правы. А если данная ф-ия будет использовться в другом объектнике, а компилятор её уже выбросил — что тогда ?

ATP> Теперь представте, что линкер отделная программа, и ей на вход приходит объектник, в котором есть функции составлящие либу. Предположим что вызывается из все только три. И как по вашему линкер (не компилятор) должен понять какие из них дейсвительно нужны, а какие нет?

Я же это кажется подробно описал.

ATP>Данный опыть совершенно не в тему....

Данный опыт бвл всего лиш не полон. Он показал что линкер по крайней мере может выбрасывать неиспользуемые объектники из либки. Я дополнил тест см. выше и выяснил, что и отдельные ф-ии он выбрасывет.

SJA>>Вывод:

SJA>>Линкер может находить одинаковые куски кода и объединять их.

ATP>Опять полная каша в голове, пулное непонимание вопроса. ЛИНКЕРРРРР — причем тут компилятор. То что вы описали делает компилятор....

Не нужно волноваться. Объединяет объектники — линкер. Две приведённые ф-ии были в разных объектниках. Их объединил линкер.

ATP>Тут далше просто какие-то рассуждения, как могло быть то, чего на самом деле нет.... или есть, но это совсем не потому, почему вы думаете. И делает это все не линкер.

Ок. В таком случае расскажите, как они это делают ? Но прежде чем расказать какую-нибудь глупость советую почитать форматы: PE32, COFF

ATP>Вы хоть раз писали на ассемблере?

Ну.... Лет 5. Но давно.

ATP>Во пример который разбивает впух и прах ваши рассуждения насчет ассеблера:


ATP>
ATP>; ...... тут хренова туча кода
ATP>....
ATP>....
ATP>....
ATP>....
ATP>call eax
ATP>


ATP>И какую я функцию интересно вызвал? Этого линкеру никогда не понять.

Это я протещу в ближайшее время.

ATP>Поэтому вывод такой, ввсе что вы описали — это антинаучно и вообще полное непонимание, того что просходит в процессе компиляции.

Конечно-конечно.
Я — свихнувшееся сознание Джо.
Re[7]: Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 23.11.04 10:03
Оценка: 6 (1)
Здравствуйте, Sergey J. A., Вы писали:

SJA>Здравствуйте, AcidTheProgrammer, Вы писали:


ATP>>Непонимаю, как на очснове данного опыта можно смделать такой поспешный вывод?!

ATP>>Да — линкер викинул либу, т.к неодна из ее функций не используется. И данный случай самый трививльный — он ниочем не говорит.
ATP>>Вот если бы вы сделали 20-ток функций, и вызывали бы их все, а потом закоментировали одну, то увидели бы, что все функции в exeшнике на месте.

SJA>Согласен. Недоделал. Однако только что попробовал вставить 2 ф-ии в либку (в один файл). Затем использовал обе и каждую по очереди. Ответственно заявляю — ВЫБРАСЫВАЕТ ! Прежде чем ответить, потрудитесь хотя бы проверить это.


Сейчас вмотрел исходники VCRT. И зачем это разработчики С++ библиотек, пихали каждую функцию в один объектник? Наверное поленились посмотреть, что их же линкер итак все выбрасывает...

SJA>>>Линкер выбрасывает ненужные ф-ии из объектных файлов.


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

SJA>Боюсь тут ты не правы. А если данная ф-ия будет использовться в другом объектнике, а компилятор её уже выбросил — что тогда ?

В чем я неправ — да компилятор выкидывае неиспользуемые функции. Но только, те за которые дейсвительно нигде не используются. Компилятор не может выкинуть используемые функции, иначе это нонсенс! А если функция используется в другом объектнике, то как минимум ее нужно описать как extern и естественно такиефункции компилятор не выкинет.

ATP>> Теперь представте, что линкер отделная программа, и ей на вход приходит объектник, в котором есть функции составлящие либу. Предположим что вызывается из все только три. И как по вашему линкер (не компилятор) должен понять какие из них дейсвительно нужны, а какие нет?

SJA>Я же это кажется подробно описал.

Вы описали алгоритм разбора машинног кода, где определяется какой кусок кода нужен, а какой нет? Что то я незаметил..

SJA>>>Вывод:

SJA>>>Линкер может находить одинаковые куски кода и объединять их.

ATP>>Опять полная каша в голове, пулное непонимание вопроса. ЛИНКЕРРРРР — причем тут компилятор. То что вы описали делает компилятор....

SJA>Не нужно волноваться. Объединяет объектники — линкер. Две приведённые ф-ии были в разных объектниках. Их объединил линкер.

В этом случае — согласен. Но этор примитивнейшая задача, если два объектника побайтно равны.

ATP>>Тут далше просто какие-то рассуждения, как могло быть то, чего на самом деле нет.... или есть, но это совсем не потому, почему вы думаете. И делает это все не линкер.

SJA>Ок. В таком случае расскажите, как они это делают ? Но прежде чем расказать какую-нибудь глупость советую почитать форматы: PE32, COFF

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

В общем ваши странные тесты не вносят никокой ясности. Это все равно что сказать, что я знаю что это так, но почему??
Собственно вопрос был, как он это делает, если делает вообще.
Re[4]: Линкер
От: LaptevVV Россия  
Дата: 23.11.04 10:25
Оценка: +1
Здравствуйте, AcidTheProgrammer, Вы писали:

SJA>>В действительности стандарт C++ это не оговаривает. Поэтому каждый производитель сам решает что и как в данной ситуации делать.

SJA>>Майкрософтовский линкер (по крайней мере от VC 6.0 и далее) выбрасывает не использующиеся ф-ии.
ATP>Выбрасывает из исходного кода, во время компиляции — да, а из линкуемой либы — вопрос?
ATP>есть либа:
ATP>1. Глобальная таблица данных
ATP>2. Функция 1
ATP>3. Функция 2
ATP>4. Функция 3

ATP>Предположим все три фукции используют глобальные данные и что мы используем только функцию 2 из либы.

ATP>Получается, что мы должны выкинуть функции 1 и 3. А может и не должны, т.к как они могут вызываться из функции в функции которая вызывается в Функции 2? А если должны выкинуть, то смещения на глобальные данные изменится, и относительные адреса не помогут. Так как же линкер поступит в этом случае?

ATP>Есть ли действительно компетентные специалисты в данном вопросе, которые могли бы помоч разобраться мне в данном вопросе?


1. Не путайте объектный модуль и отдельную функцию. В либе хранятся объектные модули. Каждый объектный модуль обязательно содержит 2 словаря: импортируемых и экспортируемых имен. Имена функций туда входят по умолчанию.
2. Типичная организация либы — блоки переменной длины. В начале каждого блока — справочник со смещениями объектных модулей от начала блока (или файла). Поэтому вытащить отдельный объектный модуль линкеру труда не представляет.
3. Не знаю как в стандартных либах, но я сделал бы по отдельному объектному модулю на функцию. Тогда линкер вытаскивает отдельный модуль со своими словарями и по словарям узнает имена необходимых функций.

Читать структуру заголовка объектного модуля — там вся инфа про модуль расписана.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[5]: Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 23.11.04 10:33
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, AcidTheProgrammer, Вы писали:


SJA>>>В действительности стандарт C++ это не оговаривает. Поэтому каждый производитель сам решает что и как в данной ситуации делать.

SJA>>>Майкрософтовский линкер (по крайней мере от VC 6.0 и далее) выбрасывает не использующиеся ф-ии.
ATP>>Выбрасывает из исходного кода, во время компиляции — да, а из линкуемой либы — вопрос?
ATP>>есть либа:
ATP>>1. Глобальная таблица данных
ATP>>2. Функция 1
ATP>>3. Функция 2
ATP>>4. Функция 3

ATP>>Предположим все три фукции используют глобальные данные и что мы используем только функцию 2 из либы.

ATP>>Получается, что мы должны выкинуть функции 1 и 3. А может и не должны, т.к как они могут вызываться из функции в функции которая вызывается в Функции 2? А если должны выкинуть, то смещения на глобальные данные изменится, и относительные адреса не помогут. Так как же линкер поступит в этом случае?

ATP>>Есть ли действительно компетентные специалисты в данном вопросе, которые могли бы помоч разобраться мне в данном вопросе?


LVV>1. Не путайте объектный модуль и отдельную функцию. В либе хранятся объектные модули. Каждый объектный модуль обязательно содержит 2 словаря: импортируемых и экспортируемых имен. Имена функций туда входят по умолчанию.

LVV>2. Типичная организация либы — блоки переменной длины. В начале каждого блока — справочник со смещениями объектных модулей от начала блока (или файла). Поэтому вытащить отдельный объектный модуль линкеру труда не представляет.
LVV>3. Не знаю как в стандартных либах, но я сделал бы по отдельному объектному модулю на функцию. Тогда линкер вытаскивает отдельный модуль со своими словарями и по словарям узнает имена необходимых функций.

LVV>Читать структуру заголовка объектного модуля — там вся инфа про модуль расписана.


Если линкер оперирует модулями — то все становится на свои места. Тогда все прозрачно.
Но просто тут человек утверджает что у него линкер выкидывает неиспользуемые функции из одного объектника

SJA>>Линкер выбрасывает ненужные ф-ии из объектных файлов.


и даже поясняет как он это делает
Re[6]: Линкер
От: LaptevVV Россия  
Дата: 23.11.04 10:41
Оценка:
Здравствуйте, AcidTheProgrammer, Вы писали:

ATP>Если линкер оперирует модулями — то все становится на свои места. Тогда все прозрачно.

ATP>Но просто тут человек утверджает что у него линкер выкидывает неиспользуемые функции из одного объектника

SJA>>>Линкер выбрасывает ненужные ф-ии из объектных файлов.


ATP>и даже поясняет как он это делает

Не, единица трансляции превращается в объектный модуль и линкер работает с ним целиком. Другое дело, что стандартные модули, как я уже говорил, можно таким образом состряпать, что прицепляться будет минимум.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[7]: Линкер
От: AcidTheProgrammer Россия https://hts.tv/
Дата: 23.11.04 10:46
Оценка:
Здравствуйте, LaptevVV, Вы писали:

LVV>Здравствуйте, AcidTheProgrammer, Вы писали:


ATP>>Если линкер оперирует модулями — то все становится на свои места. Тогда все прозрачно.

ATP>>Но просто тут человек утверджает что у него линкер выкидывает неиспользуемые функции из одного объектника

SJA>>>>Линкер выбрасывает ненужные ф-ии из объектных файлов.


ATP>>и даже поясняет как он это делает

LVV>Не, единица трансляции превращается в объектный модуль и линкер работает с ним целиком. Другое дело, что стандартные модули, как я уже говорил, можно таким образом состряпать, что прицепляться будет минимум.

Спасибо большое за ответ. Теперь все стало понятно и ясно. Теперб понятно, что ликер, как собственно и должно быть — тупая прога — смотрит что надо, смотрит в каких объектниках есть, то что надо, и включает их целиком, и не обладает искуственным интеллектом, как, я смотрю, думают многие.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.