Skip to content

Commit 22ee2a3

Browse files
committed
drivers: construct driver list at runtime
Relying on linker politeness could fail when compiled with -flto : https://sigrok.org/bugzilla/show_bug.cgi?id=1433 Instead of using a special section that holds a pointer to each of the driver descriptors, use "__attribute__((constructor))" to run a certain function at runtime just before main() entry. That is also before glib init and possibly (unclear) before heap is usable, so it may not be possible to directly build a GArray or GSList. A simple linked-list provides the intermediarey step, and sr_drivers_init() still builds the final driver list via a GArray. This compiler attribute is well-supported by gcc and clang. The SR_REGISTER_DEV_DRIVER_LIST() implementation is also not very elegant, but is a drop-in replacement.
1 parent c78fa9c commit 22ee2a3

File tree

5 files changed

+63
-111
lines changed

5 files changed

+63
-111
lines changed

Makefile.am

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -216,22 +216,16 @@ libsigrok_la_SOURCES += \
216216
src/scale/kern.c
217217

218218
# Hardware drivers
219-
noinst_LTLIBRARIES = src/libdrivers.la \
220-
src/libdrivers_head.la src/libdrivers_tail.la
219+
noinst_LTLIBRARIES = src/libdrivers.la
220+
221+
src/libdrivers.o: src/libdrivers.la
222+
$(AM_V_CCLD)$(LINK) src/libdrivers.la
221223

222-
src/libdrivers.o: src/libdrivers.la \
223-
src/libdrivers_head.la src/libdrivers_tail.la
224-
$(AM_V_CCLD)$(LINK) src/libdrivers_head.la src/libdrivers.la \
225-
src/libdrivers_tail.la
226224
src/libdrivers.lo: src/libdrivers.o
227225
$(AM_V_GEN)echo "# Generated by libtool" > $@
228226
$(AM_V_at)echo "pic_object='libdrivers.o'" >> $@
229227
$(AM_V_at)echo "non_pic_object='libdrivers.o'" >> $@
230228

231-
src_libdrivers_head_la_SOURCES = src/driver_list_start.c
232-
233-
src_libdrivers_tail_la_SOURCES = src/driver_list_stop.c
234-
235229
src_libdrivers_la_SOURCES = src/drivers.c
236230

237231
if HW_AGILENT_DMM

src/driver_list_start.c

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/driver_list_stop.c

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/drivers.c

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Copyright (C) 2016 Lars-Peter Clausen <[email protected]>
55
* Copyright (C) 2016 Aurelien Jacobs <[email protected]>
66
* Copyright (C) 2017 Marcus Comstedt <[email protected]>
7+
* Copyright (C) 2023 fenugrec <[email protected]>
78
*
89
* This program is free software: you can redistribute it and/or modify
910
* it under the terms of the GNU General Public License as published by
@@ -24,16 +25,28 @@
2425
#include <libsigrok/libsigrok.h>
2526
#include "libsigrok-internal.h"
2627

27-
/*
28-
* The special __sr_driver_list section contains pointers to all hardware
29-
* drivers which were built into the library according to its configuration
30-
* (will depend on the availability of dependencies, as well as user provided
31-
* specs). The __start and __stop symbols point to the start and end of the
32-
* section. They are used to iterate over the list of all drivers which were
33-
* included in the library.
28+
static struct device_node *devlist_head = NULL;
29+
30+
/* constructors will call this, before main() and GLib init.
31+
* We only assume static variables were initialized (i.e. contents of .bss
32+
* and .data sections).
3433
*/
35-
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__start[];
36-
SR_PRIV extern const struct sr_dev_driver *sr_driver_list__stop[];
34+
void sr_register_dev_node(struct device_node *devnode) {
35+
devnode->next = devlist_head;
36+
devlist_head = devnode;
37+
}
38+
39+
void sr_register_dev_array(struct sr_dev_driver *driver_array[], struct device_node *node_array, unsigned num) {
40+
unsigned i;
41+
struct device_node *dnode;
42+
43+
for (i = 0; i < num; i++) {
44+
dnode = &node_array[i];
45+
dnode->dev = driver_array[i];
46+
sr_register_dev_node(dnode);
47+
}
48+
}
49+
3750

3851
/**
3952
* Initialize the driver list in a fresh libsigrok context.
@@ -48,9 +61,9 @@ SR_API void sr_drivers_init(struct sr_context *ctx)
4861

4962
array = g_array_new(TRUE, FALSE, sizeof(struct sr_dev_driver *));
5063
#ifdef HAVE_DRIVERS
51-
for (const struct sr_dev_driver **drivers = sr_driver_list__start + 1;
52-
drivers < sr_driver_list__stop; drivers++)
53-
g_array_append_val(array, *drivers);
64+
for (struct device_node *cur = devlist_head; cur; cur = cur->next) {
65+
g_array_append_val(array, cur->dev);
66+
}
5467
#endif
5568
ctx->driver_list = (struct sr_dev_driver **)g_array_free(array, FALSE);
5669
}

src/libsigrok-internal.h

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1127,20 +1127,28 @@ static inline void write_dblle_inc(uint8_t **p, double x)
11271127
#define ALL_ZERO { 0 }
11281128
#endif
11291129

1130-
#ifdef __APPLE__
1131-
#define SR_DRIVER_LIST_SECTION "__DATA,__sr_driver_list"
1132-
#else
1133-
#define SR_DRIVER_LIST_SECTION "__sr_driver_list"
1134-
#endif
11351130

1136-
#if !defined SR_DRIVER_LIST_NOREORDER && defined __has_attribute
1137-
#if __has_attribute(no_reorder)
1138-
#define SR_DRIVER_LIST_NOREORDER __attribute__((no_reorder))
1139-
#endif
1140-
#endif
1141-
#if !defined SR_DRIVER_LIST_NOREORDER
1142-
#define SR_DRIVER_LIST_NOREORDER /* EMPTY */
1143-
#endif
1131+
/* constructors will assemble a LL with every driver.
1132+
* Every driver defines one of these struct by using one of the
1133+
* SR_REGISTER_DEV_DRIVER_* macros below.
1134+
* This could be greatly simplified if struct sr_dev_driver had a '->next' member. Maybe someday.
1135+
*/
1136+
struct device_node {
1137+
struct sr_dev_driver *dev;
1138+
struct device_node *next;
1139+
};
1140+
1141+
/** should only be called via SR_REGISTER_DEV_DRIVER_LIST() macro */
1142+
void sr_register_dev_array(struct sr_dev_driver *driver_array[], struct device_node *node_array, unsigned num);
1143+
1144+
/** should only be called via SR_REGISTER_DEV_DRIVER() macro */
1145+
void sr_register_dev_node(struct device_node *devnode);
1146+
1147+
1148+
/* glib uses this internally but doesn't seem to make it available.
1149+
* This is a much simplified def that will only work on gcc/clang.
1150+
*/
1151+
#define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void);
11441152

11451153
/**
11461154
* Register a list of hardware drivers.
@@ -1170,13 +1178,14 @@ static inline void write_dblle_inc(uint8_t **p, double x)
11701178
* @param ... Comma separated list of pointers to sr_dev_driver structs.
11711179
*/
11721180
#define SR_REGISTER_DEV_DRIVER_LIST(name, ...) \
1173-
static const struct sr_dev_driver *name[] \
1174-
SR_DRIVER_LIST_NOREORDER \
1175-
__attribute__((section (SR_DRIVER_LIST_SECTION), used, \
1176-
aligned(sizeof(struct sr_dev_driver *)))) \
1177-
= { \
1178-
__VA_ARGS__ \
1179-
};
1181+
static struct sr_dev_driver *name[] = { \
1182+
__VA_ARGS__ \
1183+
}; \
1184+
static struct device_node name##_nodes[ARRAY_SIZE(name)]; \
1185+
G_DEFINE_CONSTRUCTOR(register_##name) \
1186+
static void register_##name(void) { \
1187+
sr_register_dev_array(name, name##_nodes, ARRAY_SIZE(name)); \
1188+
}
11801189

11811190
/**
11821191
* Register a hardware driver.
@@ -1200,7 +1209,11 @@ static inline void write_dblle_inc(uint8_t **p, double x)
12001209
* @param name Identifier name of sr_dev_driver struct to register.
12011210
*/
12021211
#define SR_REGISTER_DEV_DRIVER(name) \
1203-
SR_REGISTER_DEV_DRIVER_LIST(name##_list, &name);
1212+
static struct device_node name##_node = { .dev = &name }; \
1213+
G_DEFINE_CONSTRUCTOR(register_##name) \
1214+
static void register_##name(void) { \
1215+
sr_register_dev_node(&name##_node); \
1216+
}
12041217

12051218
SR_API void sr_drivers_init(struct sr_context *context);
12061219

0 commit comments

Comments
 (0)