1f556a7e3SXinliang David Li /*===- InstrProfilingPlatformLinux.c - Profile data Linux platform ------===*\
2f556a7e3SXinliang David Li |*
32946cd70SChandler Carruth |* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth |* See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f556a7e3SXinliang David Li |*
7f556a7e3SXinliang David Li \*===----------------------------------------------------------------------===*/
8f556a7e3SXinliang David Li 
947e5fcbaSPetr Hosek #if defined(__linux__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
10*2407c13aSWael Yehia     (defined(__sun__) && defined(__svr4__)) || defined(__NetBSD__) || \
11*2407c13aSWael Yehia     defined(_AIX)
125b0d5b45SVedant Kumar 
13*2407c13aSWael Yehia #if !defined(_AIX)
14e50a3884SGulfem Savrun Yeniceri #include <elf.h>
15e50a3884SGulfem Savrun Yeniceri #include <link.h>
16*2407c13aSWael Yehia #endif
17e8e8599aSVedant Kumar #include <stdlib.h>
18e50a3884SGulfem Savrun Yeniceri #include <string.h>
19e8e8599aSVedant Kumar 
20d7c9336aSVedant Kumar #include "InstrProfiling.h"
21e50a3884SGulfem Savrun Yeniceri #include "InstrProfilingInternal.h"
22d7c9336aSVedant Kumar 
23440d9712SDimitry Andric #if defined(__FreeBSD__) && !defined(ElfW)
24440d9712SDimitry Andric /*
25440d9712SDimitry Andric  * FreeBSD's elf.h and link.h headers do not define the ElfW(type) macro yet.
26440d9712SDimitry Andric  * If this is added to all supported FreeBSD versions in the future, this
27440d9712SDimitry Andric  * compatibility macro can be removed.
28440d9712SDimitry Andric  */
29440d9712SDimitry Andric #define ElfW(type) __ElfN(type)
30440d9712SDimitry Andric #endif
31440d9712SDimitry Andric 
32987d331fSReid Kleckner #define PROF_DATA_START INSTR_PROF_SECT_START(INSTR_PROF_DATA_COMMON)
33987d331fSReid Kleckner #define PROF_DATA_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_DATA_COMMON)
34987d331fSReid Kleckner #define PROF_NAME_START INSTR_PROF_SECT_START(INSTR_PROF_NAME_COMMON)
35987d331fSReid Kleckner #define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_COMMON)
36987d331fSReid Kleckner #define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_COMMON)
37987d331fSReid Kleckner #define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_COMMON)
38e73ae9a1SManman Ren #define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON)
39987d331fSReid Kleckner #define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_COMMON)
40987d331fSReid Kleckner #define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_COMMON)
417c7f1201SXinliang David Li 
427c7f1201SXinliang David Li /* Declare section start and stop symbols for various sections
435a3b380fSVitaly Buka  * generated by compiler instrumentation.
447c7f1201SXinliang David Li  */
45833d4d8eSFangrui Song extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY
46833d4d8eSFangrui Song     COMPILER_RT_WEAK;
47833d4d8eSFangrui Song extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY
48833d4d8eSFangrui Song     COMPILER_RT_WEAK;
49f2147375SEllis Hoag extern char PROF_CNTS_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
50f2147375SEllis Hoag extern char PROF_CNTS_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
51833d4d8eSFangrui Song extern uint32_t PROF_ORDERFILE_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
52833d4d8eSFangrui Song extern char PROF_NAME_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
53833d4d8eSFangrui Song extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
54833d4d8eSFangrui Song extern ValueProfNode PROF_VNODES_START COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
55833d4d8eSFangrui Song extern ValueProfNode PROF_VNODES_STOP COMPILER_RT_VISIBILITY COMPILER_RT_WEAK;
565a3b380fSVitaly Buka 
57abfd553cSXinliang David Li COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_begin_data(void)58f556a7e3SXinliang David Li __llvm_profile_begin_data(void) {
597c7f1201SXinliang David Li   return &PROF_DATA_START;
60f556a7e3SXinliang David Li }
61abfd553cSXinliang David Li COMPILER_RT_VISIBILITY const __llvm_profile_data *
__llvm_profile_end_data(void)62f556a7e3SXinliang David Li __llvm_profile_end_data(void) {
637c7f1201SXinliang David Li   return &PROF_DATA_STOP;
64f556a7e3SXinliang David Li }
__llvm_profile_begin_names(void)65abfd553cSXinliang David Li COMPILER_RT_VISIBILITY const char *__llvm_profile_begin_names(void) {
667c7f1201SXinliang David Li   return &PROF_NAME_START;
67f556a7e3SXinliang David Li }
__llvm_profile_end_names(void)68abfd553cSXinliang David Li COMPILER_RT_VISIBILITY const char *__llvm_profile_end_names(void) {
697c7f1201SXinliang David Li   return &PROF_NAME_STOP;
70f556a7e3SXinliang David Li }
__llvm_profile_begin_counters(void)71f2147375SEllis Hoag COMPILER_RT_VISIBILITY char *__llvm_profile_begin_counters(void) {
727c7f1201SXinliang David Li   return &PROF_CNTS_START;
73f556a7e3SXinliang David Li }
__llvm_profile_end_counters(void)74f2147375SEllis Hoag COMPILER_RT_VISIBILITY char *__llvm_profile_end_counters(void) {
757c7f1201SXinliang David Li   return &PROF_CNTS_STOP;
76f556a7e3SXinliang David Li }
__llvm_profile_begin_orderfile(void)77e73ae9a1SManman Ren COMPILER_RT_VISIBILITY uint32_t *__llvm_profile_begin_orderfile(void) {
78e73ae9a1SManman Ren   return &PROF_ORDERFILE_START;
79e73ae9a1SManman Ren }
804e8754d2SXinliang David Li 
814e8754d2SXinliang David Li COMPILER_RT_VISIBILITY ValueProfNode *
__llvm_profile_begin_vnodes(void)824e8754d2SXinliang David Li __llvm_profile_begin_vnodes(void) {
834e8754d2SXinliang David Li   return &PROF_VNODES_START;
844e8754d2SXinliang David Li }
__llvm_profile_end_vnodes(void)857b413934SXinliang David Li COMPILER_RT_VISIBILITY ValueProfNode *__llvm_profile_end_vnodes(void) {
864e8754d2SXinliang David Li   return &PROF_VNODES_STOP;
874e8754d2SXinliang David Li }
887b413934SXinliang David Li COMPILER_RT_VISIBILITY ValueProfNode *CurrentVNode = &PROF_VNODES_START;
897b413934SXinliang David Li COMPILER_RT_VISIBILITY ValueProfNode *EndVNode = &PROF_VNODES_STOP;
907b413934SXinliang David Li 
91779714f8SRainer Orth #ifdef NT_GNU_BUILD_ID
RoundUp(size_t size,size_t align)92e50a3884SGulfem Savrun Yeniceri static size_t RoundUp(size_t size, size_t align) {
93e50a3884SGulfem Savrun Yeniceri   return (size + align - 1) & ~(align - 1);
94e50a3884SGulfem Savrun Yeniceri }
95e50a3884SGulfem Savrun Yeniceri 
96e50a3884SGulfem Savrun Yeniceri /*
97e50a3884SGulfem Savrun Yeniceri  * Write binary id length and then its data, because binary id does not
98e50a3884SGulfem Savrun Yeniceri  * have a fixed length.
99e50a3884SGulfem Savrun Yeniceri  */
WriteOneBinaryId(ProfDataWriter * Writer,uint64_t BinaryIdLen,const uint8_t * BinaryIdData,uint64_t BinaryIdPadding)1006c0e6f91SGulfem Savrun Yeniceri static int WriteOneBinaryId(ProfDataWriter *Writer, uint64_t BinaryIdLen,
101b9f547e8SLeonard Chan                             const uint8_t *BinaryIdData,
102b9f547e8SLeonard Chan                             uint64_t BinaryIdPadding) {
103e50a3884SGulfem Savrun Yeniceri   ProfDataIOVec BinaryIdIOVec[] = {
104e50a3884SGulfem Savrun Yeniceri       {&BinaryIdLen, sizeof(uint64_t), 1, 0},
105b9f547e8SLeonard Chan       {BinaryIdData, sizeof(uint8_t), BinaryIdLen, 0},
106b9f547e8SLeonard Chan       {NULL, sizeof(uint8_t), BinaryIdPadding, 1},
107b9f547e8SLeonard Chan   };
108e50a3884SGulfem Savrun Yeniceri   if (Writer->Write(Writer, BinaryIdIOVec,
109e50a3884SGulfem Savrun Yeniceri                     sizeof(BinaryIdIOVec) / sizeof(*BinaryIdIOVec)))
110e50a3884SGulfem Savrun Yeniceri     return -1;
111e50a3884SGulfem Savrun Yeniceri 
112e50a3884SGulfem Savrun Yeniceri   /* Successfully wrote binary id, report success. */
113e50a3884SGulfem Savrun Yeniceri   return 0;
114e50a3884SGulfem Savrun Yeniceri }
115e50a3884SGulfem Savrun Yeniceri 
116e50a3884SGulfem Savrun Yeniceri /*
117e50a3884SGulfem Savrun Yeniceri  * Look for the note that has the name "GNU\0" and type NT_GNU_BUILD_ID
118e50a3884SGulfem Savrun Yeniceri  * that contains build id. If build id exists, write binary id.
119e50a3884SGulfem Savrun Yeniceri  *
120e50a3884SGulfem Savrun Yeniceri  * Each note in notes section starts with a struct which includes
121e50a3884SGulfem Savrun Yeniceri  * n_namesz, n_descsz, and n_type members. It is followed by the name
122e50a3884SGulfem Savrun Yeniceri  * (whose length is defined in n_namesz) and then by the descriptor
123e50a3884SGulfem Savrun Yeniceri  * (whose length is defined in n_descsz).
124e50a3884SGulfem Savrun Yeniceri  *
125e50a3884SGulfem Savrun Yeniceri  * Note sections like .note.ABI-tag and .note.gnu.build-id are aligned
126e50a3884SGulfem Savrun Yeniceri  * to 4 bytes, so round n_namesz and n_descsz to the nearest 4 bytes.
127e50a3884SGulfem Savrun Yeniceri  */
WriteBinaryIdForNote(ProfDataWriter * Writer,const ElfW (Nhdr)* Note)1286c0e6f91SGulfem Savrun Yeniceri static int WriteBinaryIdForNote(ProfDataWriter *Writer,
1296c0e6f91SGulfem Savrun Yeniceri                                 const ElfW(Nhdr) * Note) {
130e50a3884SGulfem Savrun Yeniceri   int BinaryIdSize = 0;
131e50a3884SGulfem Savrun Yeniceri   const char *NoteName = (const char *)Note + sizeof(ElfW(Nhdr));
132e50a3884SGulfem Savrun Yeniceri   if (Note->n_type == NT_GNU_BUILD_ID && Note->n_namesz == 4 &&
133e50a3884SGulfem Savrun Yeniceri       memcmp(NoteName, "GNU\0", 4) == 0) {
134e50a3884SGulfem Savrun Yeniceri     uint64_t BinaryIdLen = Note->n_descsz;
135e50a3884SGulfem Savrun Yeniceri     const uint8_t *BinaryIdData =
136e50a3884SGulfem Savrun Yeniceri         (const uint8_t *)(NoteName + RoundUp(Note->n_namesz, 4));
137b9f547e8SLeonard Chan     uint8_t BinaryIdPadding = __llvm_profile_get_num_padding_bytes(BinaryIdLen);
138b9f547e8SLeonard Chan     if (Writer != NULL && WriteOneBinaryId(Writer, BinaryIdLen, BinaryIdData,
139b9f547e8SLeonard Chan                                            BinaryIdPadding) == -1)
140e50a3884SGulfem Savrun Yeniceri       return -1;
141e50a3884SGulfem Savrun Yeniceri 
142b9f547e8SLeonard Chan     BinaryIdSize = sizeof(BinaryIdLen) + BinaryIdLen + BinaryIdPadding;
143e50a3884SGulfem Savrun Yeniceri   }
144e50a3884SGulfem Savrun Yeniceri 
145e50a3884SGulfem Savrun Yeniceri   return BinaryIdSize;
146e50a3884SGulfem Savrun Yeniceri }
147e50a3884SGulfem Savrun Yeniceri 
148e50a3884SGulfem Savrun Yeniceri /*
149e50a3884SGulfem Savrun Yeniceri  * Helper function that iterates through notes section and find build ids.
150eb115aa6SLeonard Chan  * If writer is given, write binary ids into profiles.
151e50a3884SGulfem Savrun Yeniceri  * If an error happens while writing, return -1.
152e50a3884SGulfem Savrun Yeniceri  */
WriteBinaryIds(ProfDataWriter * Writer,const ElfW (Nhdr)* Note,const ElfW (Nhdr)* NotesEnd)1536c0e6f91SGulfem Savrun Yeniceri static int WriteBinaryIds(ProfDataWriter *Writer, const ElfW(Nhdr) * Note,
154e50a3884SGulfem Savrun Yeniceri                           const ElfW(Nhdr) * NotesEnd) {
155f261e258SGulfem Savrun Yeniceri   int BinaryIdsSize = 0;
156e50a3884SGulfem Savrun Yeniceri   while (Note < NotesEnd) {
157f261e258SGulfem Savrun Yeniceri     int OneBinaryIdSize = WriteBinaryIdForNote(Writer, Note);
158f261e258SGulfem Savrun Yeniceri     if (OneBinaryIdSize == -1)
159e50a3884SGulfem Savrun Yeniceri       return -1;
160f261e258SGulfem Savrun Yeniceri     BinaryIdsSize += OneBinaryIdSize;
161e50a3884SGulfem Savrun Yeniceri 
162e50a3884SGulfem Savrun Yeniceri     /* Calculate the offset of the next note in notes section. */
163e50a3884SGulfem Savrun Yeniceri     size_t NoteOffset = sizeof(ElfW(Nhdr)) + RoundUp(Note->n_namesz, 4) +
164e50a3884SGulfem Savrun Yeniceri                         RoundUp(Note->n_descsz, 4);
165e50a3884SGulfem Savrun Yeniceri     Note = (const ElfW(Nhdr) *)((const char *)(Note) + NoteOffset);
166e50a3884SGulfem Savrun Yeniceri   }
167e50a3884SGulfem Savrun Yeniceri 
168f261e258SGulfem Savrun Yeniceri   return BinaryIdsSize;
169e50a3884SGulfem Savrun Yeniceri }
170e50a3884SGulfem Savrun Yeniceri 
171e50a3884SGulfem Savrun Yeniceri /*
172e50a3884SGulfem Savrun Yeniceri  * Write binary ids into profiles if writer is given.
173e50a3884SGulfem Savrun Yeniceri  * Return the total size of binary ids.
174e50a3884SGulfem Savrun Yeniceri  * If an error happens while writing, return -1.
175e50a3884SGulfem Savrun Yeniceri  */
__llvm_write_binary_ids(ProfDataWriter * Writer)176e50a3884SGulfem Savrun Yeniceri COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) {
177e50a3884SGulfem Savrun Yeniceri   extern const ElfW(Ehdr) __ehdr_start __attribute__((visibility("hidden")));
178e50a3884SGulfem Savrun Yeniceri   const ElfW(Ehdr) *ElfHeader = &__ehdr_start;
179e50a3884SGulfem Savrun Yeniceri   const ElfW(Phdr) *ProgramHeader =
180e50a3884SGulfem Savrun Yeniceri       (const ElfW(Phdr) *)((uintptr_t)ElfHeader + ElfHeader->e_phoff);
181e50a3884SGulfem Savrun Yeniceri 
182f261e258SGulfem Savrun Yeniceri   int TotalBinaryIdsSize = 0;
183e50a3884SGulfem Savrun Yeniceri   uint32_t I;
184e50a3884SGulfem Savrun Yeniceri   /* Iterate through entries in the program header. */
185e50a3884SGulfem Savrun Yeniceri   for (I = 0; I < ElfHeader->e_phnum; I++) {
186f261e258SGulfem Savrun Yeniceri     /* Look for the notes segment in program header entries. */
187e50a3884SGulfem Savrun Yeniceri     if (ProgramHeader[I].p_type != PT_NOTE)
188e50a3884SGulfem Savrun Yeniceri       continue;
189e50a3884SGulfem Savrun Yeniceri 
190f261e258SGulfem Savrun Yeniceri     /* There can be multiple notes segment, and examine each of them. */
191f261e258SGulfem Savrun Yeniceri     const ElfW(Nhdr) * Note;
192f261e258SGulfem Savrun Yeniceri     const ElfW(Nhdr) * NotesEnd;
193f261e258SGulfem Savrun Yeniceri     /*
194f261e258SGulfem Savrun Yeniceri      * When examining notes in file, use p_offset, which is the offset within
195f261e258SGulfem Savrun Yeniceri      * the elf file, to find the start of notes.
196f261e258SGulfem Savrun Yeniceri      */
197f261e258SGulfem Savrun Yeniceri     if (ProgramHeader[I].p_memsz == 0 ||
198f261e258SGulfem Savrun Yeniceri         ProgramHeader[I].p_memsz == ProgramHeader[I].p_filesz) {
199f261e258SGulfem Savrun Yeniceri       Note = (const ElfW(Nhdr) *)((uintptr_t)ElfHeader +
200f261e258SGulfem Savrun Yeniceri                                   ProgramHeader[I].p_offset);
201f261e258SGulfem Savrun Yeniceri       NotesEnd = (const ElfW(Nhdr) *)((const char *)(Note) +
202f261e258SGulfem Savrun Yeniceri                                       ProgramHeader[I].p_filesz);
203f261e258SGulfem Savrun Yeniceri     } else {
204f261e258SGulfem Savrun Yeniceri       /*
205f261e258SGulfem Savrun Yeniceri        * When examining notes in memory, use p_vaddr, which is the address of
206f261e258SGulfem Savrun Yeniceri        * section after loaded to memory, to find the start of notes.
207f261e258SGulfem Savrun Yeniceri        */
208f261e258SGulfem Savrun Yeniceri       Note =
209f261e258SGulfem Savrun Yeniceri           (const ElfW(Nhdr) *)((uintptr_t)ElfHeader + ProgramHeader[I].p_vaddr);
210f261e258SGulfem Savrun Yeniceri       NotesEnd =
211f261e258SGulfem Savrun Yeniceri           (const ElfW(Nhdr) *)((const char *)(Note) + ProgramHeader[I].p_memsz);
212e50a3884SGulfem Savrun Yeniceri     }
213e50a3884SGulfem Savrun Yeniceri 
214f261e258SGulfem Savrun Yeniceri     int BinaryIdsSize = WriteBinaryIds(Writer, Note, NotesEnd);
215f261e258SGulfem Savrun Yeniceri     if (TotalBinaryIdsSize == -1)
216f261e258SGulfem Savrun Yeniceri       return -1;
217f261e258SGulfem Savrun Yeniceri 
218f261e258SGulfem Savrun Yeniceri     TotalBinaryIdsSize += BinaryIdsSize;
219f261e258SGulfem Savrun Yeniceri   }
220f261e258SGulfem Savrun Yeniceri 
221f261e258SGulfem Savrun Yeniceri   return TotalBinaryIdsSize;
222e50a3884SGulfem Savrun Yeniceri }
223779714f8SRainer Orth #else /* !NT_GNU_BUILD_ID */
224779714f8SRainer Orth /*
225779714f8SRainer Orth  * Fallback implementation for targets that don't support the GNU
226779714f8SRainer Orth  * extensions NT_GNU_BUILD_ID and __ehdr_start.
227779714f8SRainer Orth  */
__llvm_write_binary_ids(ProfDataWriter * Writer)228779714f8SRainer Orth COMPILER_RT_VISIBILITY int __llvm_write_binary_ids(ProfDataWriter *Writer) {
229779714f8SRainer Orth   return 0;
230779714f8SRainer Orth }
231779714f8SRainer Orth #endif
232e50a3884SGulfem Savrun Yeniceri 
233*2407c13aSWael Yehia #if defined(_AIX)
234*2407c13aSWael Yehia // Empty stubs to allow linking object files using the registration-based scheme
235*2407c13aSWael Yehia COMPILER_RT_VISIBILITY
__llvm_profile_register_function(void * Data_)236*2407c13aSWael Yehia void __llvm_profile_register_function(void *Data_) {}
237*2407c13aSWael Yehia 
238*2407c13aSWael Yehia COMPILER_RT_VISIBILITY
__llvm_profile_register_names_function(void * NamesStart,uint64_t NamesSize)239*2407c13aSWael Yehia void __llvm_profile_register_names_function(void *NamesStart,
240*2407c13aSWael Yehia                                             uint64_t NamesSize) {}
241*2407c13aSWael Yehia 
242*2407c13aSWael Yehia // The __start_SECNAME and __stop_SECNAME symbols (for SECNAME \in
243*2407c13aSWael Yehia // {"__llvm_prf_cnts", "__llvm_prf_data", "__llvm_prf_name", "__llvm_prf_vnds"})
244*2407c13aSWael Yehia // are always live when linking on AIX, regardless if the .o's being linked
245*2407c13aSWael Yehia // reference symbols from the profile library (for example when no files were
246*2407c13aSWael Yehia // compiled with -fprofile-generate). That's because these symbols are kept
247*2407c13aSWael Yehia // alive through references in constructor functions that are always live in the
248*2407c13aSWael Yehia // default linking model on AIX (-bcdtors:all). The __start_SECNAME and
249*2407c13aSWael Yehia // __stop_SECNAME symbols are only resolved by the linker when the SECNAME
250*2407c13aSWael Yehia // section exists. So for the scenario where the user objects have no such
251*2407c13aSWael Yehia // section (i.e. when they are compiled with -fno-profile-generate), we always
252*2407c13aSWael Yehia // define these zero length variables in each of the above 4 sections.
253*2407c13aSWael Yehia COMPILER_RT_VISIBILITY int dummy_cnts[0] COMPILER_RT_SECTION(
254*2407c13aSWael Yehia     COMPILER_RT_SEG INSTR_PROF_CNTS_SECT_NAME);
255*2407c13aSWael Yehia COMPILER_RT_VISIBILITY int dummy_data[0] COMPILER_RT_SECTION(
256*2407c13aSWael Yehia     COMPILER_RT_SEG INSTR_PROF_DATA_SECT_NAME);
257*2407c13aSWael Yehia COMPILER_RT_VISIBILITY const int dummy_name[0] COMPILER_RT_SECTION(
258*2407c13aSWael Yehia     COMPILER_RT_SEG INSTR_PROF_NAME_SECT_NAME);
259*2407c13aSWael Yehia COMPILER_RT_VISIBILITY int dummy_vnds[0] COMPILER_RT_SECTION(
260*2407c13aSWael Yehia     COMPILER_RT_SEG INSTR_PROF_VNODES_SECT_NAME);
261*2407c13aSWael Yehia 
262*2407c13aSWael Yehia // Create a fake reference to avoid GC'ing of the dummy variables by the linker.
263*2407c13aSWael Yehia // Ideally, we create a ".ref" of each variable inside the function
264*2407c13aSWael Yehia // __llvm_profile_begin_counters(), but there's no source level construct
265*2407c13aSWael Yehia // that allows us to generate that.
keep()266*2407c13aSWael Yehia __attribute__((destructor)) void keep() {
267*2407c13aSWael Yehia   int volatile use = &dummy_cnts < &dummy_data && &dummy_name < &dummy_vnds;
268*2407c13aSWael Yehia   (void)use;
269*2407c13aSWael Yehia }
270*2407c13aSWael Yehia #endif
271*2407c13aSWael Yehia 
272f556a7e3SXinliang David Li #endif
273