summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Turner <mattst88@gmail.com>2016-12-14 16:04:26 -0800
committerMatt Turner <mattst88@gmail.com>2016-12-14 16:19:48 -0800
commit838ebbcf92352217ea7ed16e0894ea585a357f88 (patch)
treef4a4a1217c84210da3f785e0836d23ab10e5896e
parent9728a8bdc1d882acf534df6a86dbb435146a5ca8 (diff)
Use dl_iterate_phdr() instead of a linker script.
According to Mike Frysinger [1] it is not reliable to read ELF sections at runtime, which the previous method involving the linker script was doing. Instead, use dl_iterate_phdr() to find the build id. [1] https://sourceware.org/ml/binutils/2016-12/msg00207.html
-rw-r--r--Makefile4
-rw-r--r--build-id.c96
-rw-r--r--build-id.h23
-rw-r--r--build-id.lds9
-rw-r--r--so-test.c20
-rw-r--r--test.c18
6 files changed, 79 insertions, 91 deletions
diff --git a/Makefile b/Makefile
index 798da5b..5c4295f 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,7 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.
-LDFLAGS = -Wl,--build-id=sha1 -Wl,--default-script=build-id.lds
+LDFLAGS = -Wl,--build-id=sha1
all: build-id so-build-id
@@ -33,7 +33,7 @@ shared-build-id.o: build-id.c
$(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -c $^ -o $@
libbuild-id.so: shared-build-id.o
- $(CC) -Wl,-Bsymbolic $(LDFLAGS) -shared $^ -o $@
+ $(CC) $(LDFLAGS) -shared $^ -o $@
clean:
rm -f build-id so-build-id libbuild-id.so *.o
diff --git a/build-id.c b/build-id.c
index 94b2e5c..e1df0c7 100644
--- a/build-id.c
+++ b/build-id.c
@@ -22,61 +22,87 @@
* IN THE SOFTWARE.
*/
-#include <elf.h>
+#define _GNU_SOURCE
+#include <link.h>
#include <stdio.h>
+#include <stddef.h>
#include <string.h>
#include "build-id.h"
-extern const ElfW(Nhdr) __note_gnu_build_id_start[] __attribute__((weak));
-extern const ElfW(Nhdr) __note_gnu_build_id_end[] __attribute__((weak));
+#define ALIGN(val, align) (((val) + (align) - 1) & ~((align) - 1))
-void
-so_print(void)
-{
- extern char etext, edata, end;
- printf("Shared object:\n");
- printf(" program text (etext) %10p\n", &etext);
- printf(" initialized data (edata) %10p\n", &edata);
- printf(" uninitialized data (end) %10p\n", &end);
- printf(" note section start %10p\n", __note_gnu_build_id_start);
- printf(" note section end %10p\n", __note_gnu_build_id_end);
-}
+struct note {
+ ElfW(Nhdr) nhdr;
+
+ char name[4];
+ uint8_t build_id[0];
+};
-const ElfW(Nhdr) *
-build_id_find_nhdr(void)
+struct callback_data {
+ const char *name;
+ struct note *note;
+};
+
+static int
+build_id_find_nhdr_callback(struct dl_phdr_info *info, size_t size, void *data_)
{
- const ElfW(Nhdr) *nhdr = (void *)__note_gnu_build_id_start;
+ struct callback_data *data = data_;
- if (__note_gnu_build_id_start >= __note_gnu_build_id_end) {
- fprintf(stderr, "No .note section\n");
- return NULL;
- }
+ if (strcmp(info->dlpi_name, data->name) != 0)
+ return 0;
+
+ for (unsigned i = 0; i < info->dlpi_phnum; i++) {
+ if (info->dlpi_phdr[i].p_type != PT_NOTE)
+ continue;
- while (nhdr->n_type != NT_GNU_BUILD_ID)
- {
- nhdr = (ElfW(Nhdr) *)
- ((intptr_t)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz + nhdr->n_descsz);
+ struct note *note = (void *)(info->dlpi_addr +
+ info->dlpi_phdr[i].p_vaddr);
+ ptrdiff_t len = info->dlpi_phdr[i].p_filesz;
- if (nhdr >= __note_gnu_build_id_end) {
- fprintf(stderr, "No .note.gnu.build-id section found\n");
- return NULL;
+ while (len >= sizeof(struct note)) {
+ if (note->nhdr.n_type == NT_GNU_BUILD_ID &&
+ note->nhdr.n_descsz != 0 &&
+ note->nhdr.n_namesz == 4 &&
+ memcmp(note->name, "GNU", 4) == 0) {
+ data->note = note;
+ return 1;
+ }
+
+ size_t offset = sizeof(ElfW(Nhdr)) +
+ ALIGN(note->nhdr.n_namesz, 4) +
+ ALIGN(note->nhdr.n_descsz, 4);
+ note = (struct note *)((char *)note + offset);
+ len -= offset;
}
}
- return nhdr;
+ return 0;
+}
+
+const struct note *
+build_id_find_nhdr(const char *name)
+{
+ struct callback_data data = {
+ .name = name,
+ .note = NULL,
+ };
+
+ if (dl_iterate_phdr(build_id_find_nhdr_callback, &data)) {
+ return data.note;
+ } else {
+ return NULL;
+ }
}
ElfW(Word)
-build_id_length(const ElfW(Nhdr) *nhdr)
+build_id_length(const struct note *note)
{
- return nhdr->n_descsz;
+ return note->nhdr.n_descsz;
}
void
-build_id_read(const ElfW(Nhdr) *nhdr, unsigned char *build_id)
+build_id_read(const struct note *note, unsigned char *build_id)
{
- memcpy(build_id,
- (unsigned char *)nhdr + sizeof(ElfW(Nhdr)) + nhdr->n_namesz,
- nhdr->n_descsz);
+ memcpy(build_id, note->build_id, note->nhdr.n_descsz);
}
diff --git a/build-id.h b/build-id.h
index 7a51c1e..03e2684 100644
--- a/build-id.h
+++ b/build-id.h
@@ -22,24 +22,17 @@
* IN THE SOFTWARE.
*/
-#include <elf.h>
-#include <stdio.h>
-#include <string.h>
+#define _GNU_SOURCE
+#include <link.h>
+#include <stdint.h>
-#if __x86_64__
-# define ElfW(type) Elf64_##type
-#else
-# define ElfW(type) Elf32_##type
-#endif
+struct note;
-void
-so_print(void);
-
-const ElfW(Nhdr) *
-build_id_find_nhdr(void);
+const struct note *
+build_id_find_nhdr(const char *name);
ElfW(Word)
-build_id_length(const ElfW(Nhdr) *nhdr);
+build_id_length(const struct note *note);
void
-build_id_read(const ElfW(Nhdr) *nhdr, unsigned char *build_id);
+build_id_read(const struct note *note, unsigned char *build_id);
diff --git a/build-id.lds b/build-id.lds
deleted file mode 100644
index 63a23f2..0000000
--- a/build-id.lds
+++ /dev/null
@@ -1,9 +0,0 @@
-SECTIONS
-{
- build-id : {
- PROVIDE(__note_gnu_build_id_start = .);
- *(.note.gnu.build-id);
- PROVIDE(__note_gnu_build_id_end = .);
- }
-}
-INSERT AFTER .note.gnu.build-id;
diff --git a/so-test.c b/so-test.c
index 0c5d74a..095fbef 100644
--- a/so-test.c
+++ b/so-test.c
@@ -30,29 +30,17 @@
int
main(int argc, char *argv[])
{
- extern char etext, edata, end;
- extern const char __note_gnu_build_id_end[] __attribute__((weak));
- extern const char __note_gnu_build_id_start[] __attribute__((weak));
- printf("Executable:\n");
- printf(" program text (etext) %10p\n", &etext);
- printf(" initialized data (edata) %10p\n", &edata);
- printf(" uninitialized data (end) %10p\n", &end);
- printf(" note section start %10p\n", __note_gnu_build_id_start);
- printf(" note section end %10p\n", __note_gnu_build_id_end);
-
- so_print();
-
- const ElfW(Nhdr) *nhdr = build_id_find_nhdr();
- if (!nhdr)
+ const struct note *note = build_id_find_nhdr("./libbuild-id.so");
+ if (!note)
return -1;
- ElfW(Word) len = build_id_length(nhdr);
+ ElfW(Word) len = build_id_length(note);
unsigned char *build_id = malloc(len * sizeof(char));
if (!build_id)
return -1;
- build_id_read(nhdr, build_id);
+ build_id_read(note, build_id);
printf("Build ID: ");
for (ElfW(Word) i = 0; i < len; i++) {
diff --git a/test.c b/test.c
index e8dae35..fbea6b4 100644
--- a/test.c
+++ b/test.c
@@ -30,27 +30,17 @@
int
main(int argc, char *argv[])
{
- extern char etext, edata, end;
- extern const char __note_gnu_build_id_end[] __attribute__((weak));
- extern const char __note_gnu_build_id_start[] __attribute__((weak));
- printf("Executable:\n");
- printf(" program text (etext) %10p\n", &etext);
- printf(" initialized data (edata) %10p\n", &edata);
- printf(" uninitialized data (end) %10p\n", &end);
- printf(" note section start %10p\n", __note_gnu_build_id_start);
- printf(" note section end %10p\n", __note_gnu_build_id_end);
-
- const ElfW(Nhdr) *nhdr = build_id_find_nhdr();
- if (!nhdr)
+ const struct note *note = build_id_find_nhdr("");
+ if (!note)
return -1;
- ElfW(Word) len = build_id_length(nhdr);
+ ElfW(Word) len = build_id_length(note);
unsigned char *build_id = malloc(len * sizeof(char));
if (!build_id)
return -1;
- build_id_read(nhdr, build_id);
+ build_id_read(note, build_id);
printf("Build ID: ");
for (ElfW(Word) i = 0; i < len; i++) {