glibc/v2-0009-x86-Check-PT_GNU_PR...

161 lines
5.1 KiB
Diff

From 4323e979bd1745e10ae29667c290bff7f74d38e4 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Thu, 13 Jan 2022 14:45:46 -0800
Subject: [PATCH v2 09/15] x86: Check PT_GNU_PROPERTY early
The PT_GNU_PROPERTY segment is scanned before PT_NOTE. For binaries
with the PT_GNU_PROPERTY segment, we can check it to avoid scan of
the PT_NOTE segment.
---
sysdeps/x86/dl-prop.h | 120 ++++++++++++++++++++++++++++--------------
1 file changed, 80 insertions(+), 40 deletions(-)
diff --git a/sysdeps/x86/dl-prop.h b/sysdeps/x86/dl-prop.h
index 87702df040..ca07b83701 100644
--- a/sysdeps/x86/dl-prop.h
+++ b/sysdeps/x86/dl-prop.h
@@ -81,6 +81,60 @@ _dl_open_check (struct link_map *m)
#endif
}
+/* Check the GNU property and return its value. It returns:
+ -1: Skip this note.
+ 0: Stop checking.
+ 1: Continue to check.
+ */
+static inline int
+_dl_check_gnu_property (unsigned int type, unsigned int datasz,
+ void *ptr, unsigned int *feature_1_and,
+ unsigned int *needed_1,
+ unsigned int *isa_1_needed)
+{
+ if (type == GNU_PROPERTY_X86_FEATURE_1_AND
+ || type == GNU_PROPERTY_X86_ISA_1_NEEDED
+ || type == GNU_PROPERTY_1_NEEDED)
+ {
+ /* The sizes of types which we are searching for are
+ 4 bytes. There is no point to continue if this
+ note is ill-formed. */
+ if (datasz != 4)
+ return -1;
+
+ /* NB: Stop the scan only after seeing all types which
+ we are searching for. */
+ _Static_assert (((GNU_PROPERTY_X86_ISA_1_NEEDED
+ > GNU_PROPERTY_X86_FEATURE_1_AND)
+ && (GNU_PROPERTY_X86_FEATURE_1_AND
+ > GNU_PROPERTY_1_NEEDED)),
+ "GNU_PROPERTY_X86_ISA_1_NEEDED > "
+ "GNU_PROPERTY_X86_FEATURE_1_AND && "
+ "GNU_PROPERTY_X86_FEATURE_1_AND > "
+ "GNU_PROPERTY_1_NEEDED");
+ if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
+ *feature_1_and = *(unsigned int *) ptr;
+ else if (type == GNU_PROPERTY_1_NEEDED)
+ *needed_1 = *(unsigned int *) ptr;
+ else
+ {
+ *isa_1_needed = *(unsigned int *) ptr;
+
+ /* Keep searching for the next GNU property note
+ generated by the older linker. */
+ return 0;
+ }
+ }
+ else if (type > GNU_PROPERTY_X86_ISA_1_NEEDED)
+ {
+ /* Stop the scan since property type is in ascending
+ order. */
+ return 0;
+ }
+
+ return 1;
+}
+
static inline void __attribute__ ((unused))
_dl_process_property_note (struct link_map *l, const ElfW(Nhdr) *note,
const ElfW(Addr) size, const ElfW(Addr) align)
@@ -141,45 +195,14 @@ _dl_process_property_note (struct link_map *l, const ElfW(Nhdr) *note,
last_type = type;
- if (type == GNU_PROPERTY_X86_FEATURE_1_AND
- || type == GNU_PROPERTY_X86_ISA_1_NEEDED
- || type == GNU_PROPERTY_1_NEEDED)
- {
- /* The sizes of types which we are searching for are
- 4 bytes. There is no point to continue if this
- note is ill-formed. */
- if (datasz != 4)
- return;
-
- /* NB: Stop the scan only after seeing all types which
- we are searching for. */
- _Static_assert (((GNU_PROPERTY_X86_ISA_1_NEEDED
- > GNU_PROPERTY_X86_FEATURE_1_AND)
- && (GNU_PROPERTY_X86_FEATURE_1_AND
- > GNU_PROPERTY_1_NEEDED)),
- "GNU_PROPERTY_X86_ISA_1_NEEDED > "
- "GNU_PROPERTY_X86_FEATURE_1_AND && "
- "GNU_PROPERTY_X86_FEATURE_1_AND > "
- "GNU_PROPERTY_1_NEEDED");
- if (type == GNU_PROPERTY_X86_FEATURE_1_AND)
- feature_1_and = *(unsigned int *) ptr;
- else if (type == GNU_PROPERTY_1_NEEDED)
- needed_1 = *(unsigned int *) ptr;
- else
- {
- isa_1_needed = *(unsigned int *) ptr;
-
- /* Keep searching for the next GNU property note
- generated by the older linker. */
- break;
- }
- }
- else if (type > GNU_PROPERTY_X86_ISA_1_NEEDED)
- {
- /* Stop the scan since property type is in ascending
- order. */
- break;
- }
+ int result = _dl_check_gnu_property (type, datasz, ptr,
+ &feature_1_and,
+ &needed_1,
+ &isa_1_needed);
+ if (result == -1)
+ return; /* Skip this note. */
+ else if (result == 0)
+ break; /* Stop checking. */
/* Check the next property item. */
ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
@@ -217,7 +240,24 @@ static inline int __attribute__ ((always_inline))
_dl_process_gnu_property (struct link_map *l, int fd, uint32_t type,
uint32_t datasz, void *data)
{
- return 0;
+ /* This is called on each GNU property. */
+ unsigned int needed_1 = 0;
+ unsigned int feature_1_and = 0;
+ unsigned int isa_1_needed = 0;
+ int result = _dl_check_gnu_property (type, datasz, data,
+ &feature_1_and, &needed_1,
+ &isa_1_needed);
+ if (needed_1 != 0)
+ l->l_1_needed = needed_1;
+ if (isa_1_needed != 0)
+ l->l_x86_isa_1_needed = isa_1_needed;
+ if (feature_1_and != 0)
+ l->l_x86_feature_1_and = feature_1_and;
+ if ((needed_1 | isa_1_needed | feature_1_and) != 0)
+ l->l_property = lc_property_valid;
+ else if (l->l_property == lc_property_unknown)
+ l->l_property = lc_property_none;
+ return result <= 0 ? 0 : result;
}
#endif /* _DL_PROP_H */
--
2.40.1