Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

objtool: Add elf_create_section_pair()

When creating an annotation section, allocate the reloc section data at
the beginning. This simplifies the data model a bit and also saves
memory due to the removal of malloc() in elf_rebuild_reloc_section().

With allyesconfig + CONFIG_DEBUG_INFO:

- Before: peak heap memory consumption: 53.49G
- After: peak heap memory consumption: 49.02G

Link: https://lore.kernel.org/r/048e908f3ede9b66c15e44672b6dda992b1dae3e.1685464332.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>

+184 -157
+7 -4
tools/objtool/arch/powerpc/include/arch/elf.h
··· 1 1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 - 3 2 #ifndef _OBJTOOL_ARCH_ELF 4 3 #define _OBJTOOL_ARCH_ELF 5 4 6 - #define R_NONE R_PPC_NONE 7 - #define R_ABS64 R_PPC64_ADDR64 8 - #define R_ABS32 R_PPC_ADDR32 5 + #define R_NONE R_PPC_NONE 6 + #define R_ABS64 R_PPC64_ADDR64 7 + #define R_ABS32 R_PPC_ADDR32 8 + #define R_DATA32 R_PPC_REL32 9 + #define R_DATA64 R_PPC64_REL64 10 + #define R_TEXT32 R_PPC_REL32 11 + #define R_TEXT64 R_PPC64_REL32 9 12 10 13 #endif /* _OBJTOOL_ARCH_ELF */
+8 -3
tools/objtool/arch/x86/include/arch/elf.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 1 2 #ifndef _OBJTOOL_ARCH_ELF 2 3 #define _OBJTOOL_ARCH_ELF 3 4 4 - #define R_NONE R_X86_64_NONE 5 - #define R_ABS64 R_X86_64_64 6 - #define R_ABS32 R_X86_64_32 5 + #define R_NONE R_X86_64_NONE 6 + #define R_ABS32 R_X86_64_32 7 + #define R_ABS64 R_X86_64_64 8 + #define R_DATA32 R_X86_64_PC32 9 + #define R_DATA64 R_X86_64_PC32 10 + #define R_TEXT32 R_X86_64_PC32 11 + #define R_TEXT64 R_X86_64_PC32 7 12 8 13 #endif /* _OBJTOOL_ARCH_ELF */
+48 -81
tools/objtool/check.c
··· 8 8 #include <inttypes.h> 9 9 #include <sys/mman.h> 10 10 11 - #include <arch/elf.h> 12 11 #include <objtool/builtin.h> 13 12 #include <objtool/cfi.h> 14 13 #include <objtool/arch.h> ··· 655 656 656 657 static int create_static_call_sections(struct objtool_file *file) 657 658 { 658 - struct section *sec; 659 659 struct static_call_site *site; 660 + struct section *sec; 660 661 struct instruction *insn; 661 662 struct symbol *key_sym; 662 663 char *key_name, *tmp; ··· 676 677 list_for_each_entry(insn, &file->static_call_list, call_node) 677 678 idx++; 678 679 679 - sec = elf_create_section(file->elf, ".static_call_sites", 680 - sizeof(struct static_call_site), idx); 680 + sec = elf_create_section_pair(file->elf, ".static_call_sites", 681 + sizeof(*site), idx, idx * 2); 681 682 if (!sec) 682 683 return -1; 683 684 684 - /* Allow modules to set the low bits of static_call_site::key */ 685 + /* Allow modules to modify the low bits of static_call_site::key */ 685 686 sec->sh.sh_flags |= SHF_WRITE; 686 687 687 688 idx = 0; 688 689 list_for_each_entry(insn, &file->static_call_list, call_node) { 689 690 690 - site = (struct static_call_site *)sec->data->d_buf + idx; 691 - memset(site, 0, sizeof(struct static_call_site)); 692 - 693 691 /* populate reloc for 'addr' */ 694 - if (elf_add_reloc_to_insn(file->elf, sec, 695 - idx * sizeof(struct static_call_site), 696 - R_X86_64_PC32, 697 - insn->sec, insn->offset)) 692 + if (!elf_init_reloc_text_sym(file->elf, sec, 693 + idx * sizeof(*site), idx * 2, 694 + insn->sec, insn->offset)) 698 695 return -1; 699 696 700 697 /* find key symbol */ ··· 730 735 free(key_name); 731 736 732 737 /* populate reloc for 'key' */ 733 - if (elf_add_reloc(file->elf, sec, 734 - idx * sizeof(struct static_call_site) + 4, 735 - R_X86_64_PC32, key_sym, 736 - is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) 738 + if (!elf_init_reloc_data_sym(file->elf, sec, 739 + idx * sizeof(*site) + 4, 740 + (idx * 2) + 1, key_sym, 741 + is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) 737 742 return -1; 738 743 739 744 idx++; ··· 761 766 if (!idx) 762 767 return 0; 763 768 764 - sec = elf_create_section(file->elf, ".retpoline_sites", 765 - sizeof(int), idx); 766 - if (!sec) { 767 - WARN("elf_create_section: .retpoline_sites"); 769 + sec = elf_create_section_pair(file->elf, ".retpoline_sites", 770 + sizeof(int), idx, idx); 771 + if (!sec) 768 772 return -1; 769 - } 770 773 771 774 idx = 0; 772 775 list_for_each_entry(insn, &file->retpoline_call_list, call_node) { 773 776 774 - int *site = (int *)sec->data->d_buf + idx; 775 - *site = 0; 776 - 777 - if (elf_add_reloc_to_insn(file->elf, sec, 778 - idx * sizeof(int), 779 - R_X86_64_PC32, 780 - insn->sec, insn->offset)) { 781 - WARN("elf_add_reloc_to_insn: .retpoline_sites"); 777 + if (!elf_init_reloc_text_sym(file->elf, sec, 778 + idx * sizeof(int), idx, 779 + insn->sec, insn->offset)) 782 780 return -1; 783 - } 784 781 785 782 idx++; 786 783 } ··· 799 812 if (!idx) 800 813 return 0; 801 814 802 - sec = elf_create_section(file->elf, ".return_sites", 803 - sizeof(int), idx); 804 - if (!sec) { 805 - WARN("elf_create_section: .return_sites"); 815 + sec = elf_create_section_pair(file->elf, ".return_sites", 816 + sizeof(int), idx, idx); 817 + if (!sec) 806 818 return -1; 807 - } 808 819 809 820 idx = 0; 810 821 list_for_each_entry(insn, &file->return_thunk_list, call_node) { 811 822 812 - int *site = (int *)sec->data->d_buf + idx; 813 - *site = 0; 814 - 815 - if (elf_add_reloc_to_insn(file->elf, sec, 816 - idx * sizeof(int), 817 - R_X86_64_PC32, 818 - insn->sec, insn->offset)) { 819 - WARN("elf_add_reloc_to_insn: .return_sites"); 823 + if (!elf_init_reloc_text_sym(file->elf, sec, 824 + idx * sizeof(int), idx, 825 + insn->sec, insn->offset)) 820 826 return -1; 821 - } 822 827 823 828 idx++; 824 829 } ··· 843 864 if (!idx) 844 865 return 0; 845 866 846 - sec = elf_create_section(file->elf, ".ibt_endbr_seal", 847 - sizeof(int), idx); 848 - if (!sec) { 849 - WARN("elf_create_section: .ibt_endbr_seal"); 867 + sec = elf_create_section_pair(file->elf, ".ibt_endbr_seal", 868 + sizeof(int), idx, idx); 869 + if (!sec) 850 870 return -1; 851 - } 852 871 853 872 idx = 0; 854 873 list_for_each_entry(insn, &file->endbr_list, call_node) { ··· 861 884 !strcmp(sym->name, "cleanup_module"))) 862 885 WARN("%s(): not an indirect call target", sym->name); 863 886 864 - if (elf_add_reloc_to_insn(file->elf, sec, 865 - idx * sizeof(int), 866 - R_X86_64_PC32, 867 - insn->sec, insn->offset)) { 868 - WARN("elf_add_reloc_to_insn: .ibt_endbr_seal"); 887 + if (!elf_init_reloc_text_sym(file->elf, sec, 888 + idx * sizeof(int), idx, 889 + insn->sec, insn->offset)) 869 890 return -1; 870 - } 871 891 872 892 idx++; 873 893 } ··· 876 902 { 877 903 struct section *sec; 878 904 struct symbol *sym; 879 - unsigned int *loc; 880 905 int idx; 881 906 882 907 sec = find_section_by_name(file->elf, ".cfi_sites"); ··· 896 923 idx++; 897 924 } 898 925 899 - sec = elf_create_section(file->elf, ".cfi_sites", sizeof(unsigned int), idx); 926 + sec = elf_create_section_pair(file->elf, ".cfi_sites", 927 + sizeof(unsigned int), idx, idx); 900 928 if (!sec) 901 929 return -1; 902 930 ··· 909 935 if (strncmp(sym->name, "__cfi_", 6)) 910 936 continue; 911 937 912 - loc = (unsigned int *)sec->data->d_buf + idx; 913 - memset(loc, 0, sizeof(unsigned int)); 914 - 915 - if (elf_add_reloc_to_insn(file->elf, sec, 916 - idx * sizeof(unsigned int), 917 - R_X86_64_PC32, 918 - sym->sec, sym->offset)) 938 + if (!elf_init_reloc_text_sym(file->elf, sec, 939 + idx * sizeof(unsigned int), idx, 940 + sym->sec, sym->offset)) 919 941 return -1; 920 942 921 943 idx++; ··· 941 971 list_for_each_entry(insn, &file->mcount_loc_list, call_node) 942 972 idx++; 943 973 944 - sec = elf_create_section(file->elf, "__mcount_loc", addr_size, idx); 974 + sec = elf_create_section_pair(file->elf, "__mcount_loc", addr_size, 975 + idx, idx); 945 976 if (!sec) 946 977 return -1; 947 978 ··· 950 979 951 980 idx = 0; 952 981 list_for_each_entry(insn, &file->mcount_loc_list, call_node) { 953 - void *loc; 954 982 955 - loc = sec->data->d_buf + idx; 956 - memset(loc, 0, addr_size); 983 + struct reloc *reloc; 957 984 958 - if (elf_add_reloc_to_insn(file->elf, sec, idx, 959 - addr_size == sizeof(u64) ? R_ABS64 : R_ABS32, 960 - insn->sec, insn->offset)) 985 + reloc = elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx, 986 + insn->sec, insn->offset); 987 + if (!reloc) 961 988 return -1; 962 989 963 - idx += addr_size; 990 + reloc->type = addr_size == 8 ? R_ABS64 : R_ABS32; 991 + 992 + idx++; 964 993 } 965 994 966 995 return 0; ··· 970 999 { 971 1000 struct instruction *insn; 972 1001 struct section *sec; 973 - unsigned int *loc; 974 1002 int idx; 975 1003 976 1004 sec = find_section_by_name(file->elf, ".call_sites"); ··· 986 1016 list_for_each_entry(insn, &file->call_list, call_node) 987 1017 idx++; 988 1018 989 - sec = elf_create_section(file->elf, ".call_sites", sizeof(unsigned int), idx); 1019 + sec = elf_create_section_pair(file->elf, ".call_sites", 1020 + sizeof(unsigned int), idx, idx); 990 1021 if (!sec) 991 1022 return -1; 992 1023 993 1024 idx = 0; 994 1025 list_for_each_entry(insn, &file->call_list, call_node) { 995 1026 996 - loc = (unsigned int *)sec->data->d_buf + idx; 997 - memset(loc, 0, sizeof(unsigned int)); 998 - 999 - if (elf_add_reloc_to_insn(file->elf, sec, 1000 - idx * sizeof(unsigned int), 1001 - R_X86_64_PC32, 1002 - insn->sec, insn->offset)) 1027 + if (!elf_init_reloc_text_sym(file->elf, sec, 1028 + idx * sizeof(unsigned int), idx, 1029 + insn->sec, insn->offset)) 1003 1030 return -1; 1004 1031 1005 1032 idx++;
+91 -60
tools/objtool/elf.c
··· 533 533 return -1; 534 534 } 535 535 536 - static struct section *elf_create_rela_section(struct elf *elf, 537 - struct section *sec); 538 - 539 - int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, 540 - unsigned int type, struct symbol *sym, s64 addend) 541 - { 542 - struct reloc *reloc; 543 - 544 - if (!sec->rsec && !elf_create_rela_section(elf, sec)) 545 - return -1; 546 - 547 - reloc = malloc(sizeof(*reloc)); 548 - if (!reloc) { 549 - perror("malloc"); 550 - return -1; 551 - } 552 - memset(reloc, 0, sizeof(*reloc)); 553 - 554 - reloc->sec = sec->rsec; 555 - reloc->offset = offset; 556 - reloc->type = type; 557 - reloc->sym = sym; 558 - reloc->addend = addend; 559 - 560 - list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list); 561 - list_add_tail(&reloc->list, &sec->rsec->reloc_list); 562 - elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); 563 - 564 - sec->rsec->sh.sh_size += sec->rsec->sh.sh_entsize; 565 - 566 - mark_sec_changed(elf, sec->rsec, true); 567 - 568 - return 0; 569 - } 570 - 571 536 /* 572 537 * Ensure that any reloc section containing references to @sym is marked 573 538 * changed such that it will get re-generated in elf_rebuild_reloc_sections() ··· 806 841 return sym; 807 842 } 808 843 809 - int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, 810 - unsigned long offset, unsigned int type, 811 - struct section *insn_sec, unsigned long insn_off) 844 + static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, 845 + unsigned int reloc_idx, 846 + unsigned long offset, struct symbol *sym, 847 + s64 addend, unsigned int type) 848 + { 849 + struct reloc *reloc; 850 + 851 + if (reloc_idx >= rsec->sh.sh_size / elf_rela_size(elf)) { 852 + WARN("%s: bad reloc_idx %u for %s with size 0x%lx", 853 + __func__, reloc_idx, rsec->name, rsec->sh.sh_size); 854 + return NULL; 855 + } 856 + 857 + reloc = malloc(sizeof(*reloc)); 858 + if (!reloc) { 859 + perror("malloc"); 860 + return NULL; 861 + } 862 + memset(reloc, 0, sizeof(*reloc)); 863 + 864 + reloc->idx = reloc_idx; 865 + reloc->sec = rsec; 866 + reloc->offset = offset; 867 + reloc->type = type; 868 + reloc->sym = sym; 869 + reloc->addend = addend; 870 + 871 + list_add_tail(&reloc->sym_reloc_entry, &sym->reloc_list); 872 + list_add_tail(&reloc->list, &rsec->reloc_list); 873 + elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); 874 + 875 + mark_sec_changed(elf, rsec, true); 876 + 877 + return reloc; 878 + } 879 + 880 + struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, 881 + unsigned long offset, 882 + unsigned int reloc_idx, 883 + struct section *insn_sec, 884 + unsigned long insn_off) 812 885 { 813 886 struct symbol *sym = insn_sec->sym; 814 887 int addend = insn_off; 888 + 889 + if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) { 890 + WARN("bad call to %s() for data symbol %s", 891 + __func__, sym->name); 892 + return NULL; 893 + } 815 894 816 895 if (!sym) { 817 896 /* ··· 866 857 */ 867 858 sym = elf_create_section_symbol(elf, insn_sec); 868 859 if (!sym) 869 - return -1; 860 + return NULL; 870 861 871 862 insn_sec->sym = sym; 872 863 } 873 864 874 - return elf_add_reloc(elf, sec, offset, type, sym, addend); 865 + return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend, 866 + elf_text_rela_type(elf)); 867 + } 868 + 869 + struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec, 870 + unsigned long offset, 871 + unsigned int reloc_idx, 872 + struct symbol *sym, 873 + s64 addend) 874 + { 875 + if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) { 876 + WARN("bad call to %s() for text symbol %s", 877 + __func__, sym->name); 878 + return NULL; 879 + } 880 + 881 + return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend, 882 + elf_data_rela_type(elf)); 875 883 } 876 884 877 885 static int read_reloc(struct section *rsec, int i, struct reloc *reloc) ··· 1074 1048 } 1075 1049 1076 1050 struct section *elf_create_section(struct elf *elf, const char *name, 1077 - size_t entsize, int nr) 1051 + size_t entsize, unsigned int nr) 1078 1052 { 1079 1053 struct section *sec, *shstrtab; 1080 1054 size_t size = entsize * nr; ··· 1155 1129 } 1156 1130 1157 1131 static struct section *elf_create_rela_section(struct elf *elf, 1158 - struct section *sec) 1132 + struct section *sec, 1133 + unsigned int reloc_nr) 1159 1134 { 1160 1135 struct section *rsec; 1161 1136 char *rsec_name; ··· 1169 1142 strcpy(rsec_name, ".rela"); 1170 1143 strcat(rsec_name, sec->name); 1171 1144 1172 - rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), 0); 1145 + rsec = elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr); 1173 1146 free(rsec_name); 1174 1147 if (!rsec) 1175 1148 return NULL; 1176 1149 1177 - sec->rsec = rsec; 1178 - rsec->base = sec; 1179 - 1150 + rsec->data->d_type = ELF_T_RELA; 1180 1151 rsec->sh.sh_type = SHT_RELA; 1181 1152 rsec->sh.sh_addralign = elf_addr_size(elf); 1182 1153 rsec->sh.sh_link = find_section_by_name(elf, ".symtab")->idx; 1183 1154 rsec->sh.sh_info = sec->idx; 1184 1155 rsec->sh.sh_flags = SHF_INFO_LINK; 1185 1156 1157 + sec->rsec = rsec; 1158 + rsec->base = sec; 1159 + 1186 1160 return rsec; 1161 + } 1162 + 1163 + struct section *elf_create_section_pair(struct elf *elf, const char *name, 1164 + size_t entsize, unsigned int nr, 1165 + unsigned int reloc_nr) 1166 + { 1167 + struct section *sec; 1168 + 1169 + sec = elf_create_section(elf, name, entsize, nr); 1170 + if (!sec) 1171 + return NULL; 1172 + 1173 + if (!elf_create_rela_section(elf, sec, reloc_nr)) 1174 + return NULL; 1175 + 1176 + return sec; 1187 1177 } 1188 1178 1189 1179 static int elf_rebuild_reloc_section(struct elf *elf, struct section *rsec) 1190 1180 { 1191 - bool rela = rsec->sh.sh_type == SHT_RELA; 1192 1181 struct reloc *reloc; 1193 1182 int idx = 0, ret; 1194 - void *buf; 1195 - 1196 - /* Allocate a buffer for relocations */ 1197 - buf = malloc(rsec->sh.sh_size); 1198 - if (!buf) { 1199 - perror("malloc"); 1200 - return -1; 1201 - } 1202 - 1203 - rsec->data->d_buf = buf; 1204 - rsec->data->d_size = rsec->sh.sh_size; 1205 - rsec->data->d_type = rela ? ELF_T_RELA : ELF_T_REL; 1206 1183 1207 1184 idx = 0; 1208 1185 list_for_each_entry(reloc, &rsec->reloc_list, list) { 1209 1186 reloc->rel.r_offset = reloc->offset; 1210 1187 reloc->rel.r_info = GELF_R_INFO(reloc->sym->idx, reloc->type); 1211 - if (rela) { 1188 + if (rsec->sh.sh_type == SHT_RELA) { 1212 1189 reloc->rela.r_addend = reloc->addend; 1213 1190 ret = gelf_update_rela(rsec->data, idx, &reloc->rela); 1214 1191 } else {
+27 -6
tools/objtool/include/objtool/elf.h
··· 111 111 }; 112 112 113 113 struct elf *elf_open_read(const char *name, int flags); 114 - struct section *elf_create_section(struct elf *elf, const char *name, size_t entsize, int nr); 114 + 115 + struct section *elf_create_section(struct elf *elf, const char *name, 116 + size_t entsize, unsigned int nr); 117 + struct section *elf_create_section_pair(struct elf *elf, const char *name, 118 + size_t entsize, unsigned int nr, 119 + unsigned int reloc_nr); 115 120 116 121 struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size); 117 122 118 - int elf_add_reloc(struct elf *elf, struct section *sec, unsigned long offset, 119 - unsigned int type, struct symbol *sym, s64 addend); 120 - int elf_add_reloc_to_insn(struct elf *elf, struct section *sec, 121 - unsigned long offset, unsigned int type, 122 - struct section *insn_sec, unsigned long insn_off); 123 + struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, 124 + unsigned long offset, 125 + unsigned int reloc_idx, 126 + struct section *insn_sec, 127 + unsigned long insn_off); 128 + 129 + struct reloc *elf_init_reloc_data_sym(struct elf *elf, struct section *sec, 130 + unsigned long offset, 131 + unsigned int reloc_idx, 132 + struct symbol *sym, 133 + s64 addend); 123 134 124 135 int elf_write_insn(struct elf *elf, struct section *sec, 125 136 unsigned long offset, unsigned int len, ··· 168 157 static inline size_t elf_rela_size(struct elf *elf) 169 158 { 170 159 return elf_addr_size(elf) == 4 ? sizeof(Elf32_Rela) : sizeof(Elf64_Rela); 160 + } 161 + 162 + static inline unsigned int elf_data_rela_type(struct elf *elf) 163 + { 164 + return elf_addr_size(elf) == 4 ? R_DATA32 : R_DATA64; 165 + } 166 + 167 + static inline unsigned int elf_text_rela_type(struct elf *elf) 168 + { 169 + return elf_addr_size(elf) == 4 ? R_TEXT32 : R_TEXT64; 171 170 } 172 171 173 172 static inline bool is_reloc_sec(struct section *sec)
+3 -3
tools/objtool/orc_gen.c
··· 118 118 orc->bp_offset = bswap_if_needed(elf, orc->bp_offset); 119 119 120 120 /* populate reloc for ip */ 121 - if (elf_add_reloc_to_insn(elf, ip_sec, idx * sizeof(int), R_X86_64_PC32, 122 - insn_sec, insn_off)) 121 + if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, 122 + insn_sec, insn_off)) 123 123 return -1; 124 124 125 125 return 0; ··· 242 242 if (!orc_sec) 243 243 return -1; 244 244 245 - sec = elf_create_section(file->elf, ".orc_unwind_ip", sizeof(int), nr); 245 + sec = elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int), nr, nr); 246 246 if (!sec) 247 247 return -1; 248 248