Не работают -ffunction-section -fdata-секции и --gc-секции? - PullRequest
0 голосов
/ 05 марта 2019

Я хочу удалить неиспользуемые функции из кода во время компиляции.Затем я пишу некоторый код (main.c):

#include <stdio.h>

const char *get1();

int main()
{
    puts( get1() );
}

и getall.c:

const char *get1()
{
    return "s97symmqdn-1";
}


const char *get2()
{
    return "s97symmqdn-2";
}

const char *get3()
{
    return "s97symmqdn-3";
}

Makefile

test1   :
        rm -f a.out *.o *.a
        gcc -ffunction-sections -fdata-sections -c main.c getall.c
        ar cr libgetall.a getall.o
        gcc -Wl,--gc-sections main.o -L. -lgetall

После запуска make test1 && objdump --sym a.out | grep get,Я нахожу только следующие 2 строки вывода:

0000000000000000 l    df *ABS*  0000000000000000              getall.c
0000000000400535 g     F .text  000000000000000b              get1

Я думаю, get2 и get3 были удалены.Но когда я открываю a.out с помощью vim, я обнаружил, что s97symmqdn-1 s97symmqdn-2 s97symmqdn-3 существует.Функция get2 get3 действительно удалена?Как я могу удалить символ s97symmqdn-2 s97symmqdn-3?Спасибо за ваш ответ.У меня система centos7 и версия gcc 4.8.5

1 Ответ

0 голосов
/ 05 марта 2019

Параметры компиляции -ffunction-sections -fdata-sections и опция связывания --gc-sections работают правильно в вашем примере.Ваша статическая библиотека лишняя, поэтому ее можно упростить до:

$ gcc -ffunction-sections -fdata-sections -c main.c getall.c
$ gcc -Wl,--gc-sections main.o getall.o -Wl,-Map=mapfile

, в которой я также запрашиваю файл компоновщика.

Неиспользуемые функции get2 и get3отсутствуют в исполняемом файле:

$ nm a.out | grep get
0000000000000657 T get1

, и файл карты показывает, что неиспользуемые функциональные секции .text.get2 и .text.get3, в которых определены get2 и get3 соответственно, были отброшены в связи:

mapfile (1)

...
Discarded input sections
...
 .text.get2     0x0000000000000000        0xd getall.o
 .text.get3     0x0000000000000000        0xd getall.o
...

Тем не менее, как вы обнаружили, все три строковых литерала "s97symmqdn-(1|2|3)" находятся в программе:

$ strings a.out | egrep 's97symmqdn-(1|2|3)'
s97symmqdn-1
s97symmqdn-2
s97symmqdn-3

Это потому, что -fdata-sections применяется только к тем же объектам данных, что __attribute__ ((__section__("name"))) применяется к 1 , то есть к определениям переменных , которыеиметь статическая продолжительность хранения .Он не применяется к анонимным строковым литералам, таким как "s97symmqdn-(1|2|3)".Все они просто помещаются в секцию .rodata как обычно, и там мы находим их:

$ objdump -s -j .rodata a.out

a.out:     file format elf64-x86-64

Contents of section .rodata:
 06ed 73393773 796d6d71 646e2d31 00733937  s97symmqdn-1.s97
 06fd 73796d6d 71646e2d 32007339 3773796d  symmqdn-2.s97sym
 070d 6d71646e 2d3300                      mqdn-3.

--gc-sections не позволяет компоновщику удалить .rodata из программы, потому что он не являетсянеиспользуемый раздел: содержит "s97symmqdn-1", на который ссылается программа get1, а также строки без ссылок "s97symmqdn-2" и "s97symmqdn-3"

Fix

Toчтобы эти три строковых литерала были разделены на отдельные разделы данных, вам нужно назначить их различным именованным объектам, например,

getcall.c (2)

const char *get1()
{
    static const char s[] = "s97symmqdn-1";
    return s;
}


const char *get2()
{
    static const char s[] = "s97symmqdn-2";
    return s;
}

const char *get3()
{
    static const char s[] = "s97symmqdn-3";
    return s;
}

Еслимы перекомпилируем и перекомпилируем это изменение, мы видим:

mapfile (2)

...
Discarded input sections
...
 .text.get2     0x0000000000000000        0xd getall.o
 .text.get3     0x0000000000000000        0xd getall.o
 .rodata.s.1797
                0x0000000000000000        0xd getall.o
 .rodata.s.1800
                0x0000000000000000        0xd getall.o
...

Теперь есть два новых отброшенных раздела данных, которые содержат дваСтроковые литералы, которые нам не нужны, как мы видим в объектном файле:

$ objdump -s -j .rodata.s.1797 getall.o

getall.o:     file format elf64-x86-64

Contents of section .rodata.s.1797:
 0000 73393773 796d6d71 646e2d32 00        s97symmqdn-2.

и:

$ objdump -s -j .rodata.s.1800 getall.o

getall.o:     file format elf64-x86-64

Contents of section .rodata.s.1800:
 0000 73393773 796d6d71 646e2d33 00        s97symmqdn-3.

В любом месте программы теперь появляется только указанная строка "s97symmqdn-1":

$ strings a.out | egrep 's97symmqdn-(1|2|3)'
s97symmqdn-1

и это единственная строка в программе .rodata:

$ objdump -s -j .rodata a.out

a.out:     file format elf64-x86-64

Contents of section .rodata:
 06f0 73393773 796d6d71 646e2d31 00        s97symmqdn-1.


[1]-function-sections имеет тот же эффект, что и определение каждой функции foo с __attribute__ ((__section__(".text.foo")))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...