Gcc: подстановка во время компоновки

В настоящее время я пытаюсь понять, как работают компилятор gcc и компоновщик. Я столкнулся с очень интересной техникой, называемой «подстановкой во время ссылки». Цель состоит в том, чтобы иметь несколько определений функции в нескольких файлах и решить, какое из этих определений войдет в окончательный исполняемый файл во время компоновки.

Простой пример:

main.c:

#include "header.h"

int main(void)
{
    hello("everyone");
    return 0;
}

header.h:

#ifndef _HEADER_H
#define _HEADER_H

void hello(const char * name);

#endif

file1.c:

#include "header.h"
#include <stdio.h>

void hello(const char * name)
{
    printf("File1: Hello, %s!\n", name);
}

file2.c:

#include "header.h"
#include <stdio.h>

void hello(const char * name)
{
    printf("File2: Hello, %s!\n", name);
}

Теперь у меня два вопроса:

  • Можно ли выбрать функцию, используя соответствующий порядок связывания (если все три файла присутствуют в списке аргументов компоновщика)?
  • Предположим, file2.c реализует множество функций, которые необходимы main.c. Можно ли заменить одну функцию или несколько функций разными реализациями в file1.c (с тем же именем) с помощью компоновщика? Компоновщик должен сначала использовать определения функций в file1.c, а затем использовать file2.c для оставшихся неразрешенных функций.

Надеюсь, мои вопросы понятны;)

Спасибо!

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

Yunnosch 15.06.2018 09:39

Не связаны с вашей проблемой и вопросом, но символы, начинающиеся с подчеркивания и за которыми следует заглавная буква (например, _HEADER_H), являются зарезервированный во всех областях для «реализации» (компилятор и стандартная библиотека).

Some programmer dude 15.06.2018 09:40

Да, я могу редактировать file2. Переключатели препроцессора, безусловно, являются решением этой проблемы, но мне было интересно, есть ли более элегантный способ, возможно, за счет умного использования компоновщика (я особенно пытаюсь понять, как порядок аргументов играет роль во время связывания).

Athazo 15.06.2018 09:45

@ Какой-то чувак-программист: Спасибо за пояснение, не знал об этом! ;)

Athazo 15.06.2018 09:57

Вы можете отметить одну функцию как слабый символ.

KamilCuk 15.06.2018 10:29
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
589
1

Ответы 1

Is it possible to select a function by using an appropriate linking order (if all three files appear in the linker's argument list)?

Если под «всеми тремя файлами» вы подразумеваете объектные файлы (и при условии отсутствия слабых символов), тогда нет: все 3 файла будут связаны, и вы получите ошибку определения повторяющегося символа.

Но если вы поместите file1.o в lib1.a, а file2.o в lib2.a, тогда да:

gcc main.c -l1 -l2  # uses file1.o:hello
gcc main.c -l2 -l1  # uses file2.o:hello

Подробнее здесь и здесь.

Suppose file2.c implements many functions which are needed by main.c. Is it possible to replace a single function or some functions by different implementations in file1.c (with the same name) by using the linker?

Да, но только на платформах, поддерживающих слабые символы (например, платформы ELF, см. __attribute__((weak))здесь).

Если все символы в file2.o определены слабо, а все символы в file1.o - нет, то связывание file1.o и file2.o приведет к желаемому результату: сильные символы выигрывают.

Я считаю (но не тестировал), что если оба file1.o и file2.o слабо определяют одни и те же символы, то порядок будет иметь значение:

gcc main.c file1.o file2.o  # file1.o definitions override file2.o
gcc main.c file2.o file1.o  # file2.o definitions override file1.o

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