Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus
* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: params.c: Use new strtobool function to process boolean inputs debugfs: move to new strtobool Add a strtobool function matching semantics of existing in kernel equivalents modpost: Update 64k section support for binutils 2.18.50 module: Use binary search in lookup_symbol() module: Use the binary search for symbols resolution lib: Add generic binary search function to the kernel. module: Sort exported symbols module: each_symbol_section instead of each_symbol module: split unset_section_ro_nx function. module: undo module RONX protection correctly. module: zero mod->init_ro_size after init is freed. minor ANSI prototype sparse fix module: reorder kparam_array to remove alignment padding on 64 bit builds module: remove 64 bit alignment padding from struct module with CONFIG_TRACE* module: do not hide __modver_version_show declaration behind ifdef module: deal with alignment issues in built-in module versions
This commit is contained in:
@@ -11,5 +11,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable);
|
|||||||
int set_memory_ro(unsigned long addr, int numpages);
|
int set_memory_ro(unsigned long addr, int numpages);
|
||||||
int set_memory_rw(unsigned long addr, int numpages);
|
int set_memory_rw(unsigned long addr, int numpages);
|
||||||
int set_memory_nx(unsigned long addr, int numpages);
|
int set_memory_nx(unsigned long addr, int numpages);
|
||||||
|
int set_memory_x(unsigned long addr, int numpages);
|
||||||
|
|
||||||
#endif /* _S390_CACHEFLUSH_H */
|
#endif /* _S390_CACHEFLUSH_H */
|
||||||
|
@@ -54,3 +54,8 @@ int set_memory_nx(unsigned long addr, int numpages)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(set_memory_nx);
|
EXPORT_SYMBOL_GPL(set_memory_nx);
|
||||||
|
|
||||||
|
int set_memory_x(unsigned long addr, int numpages)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -429,24 +429,15 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
|
|||||||
{
|
{
|
||||||
char buf[32];
|
char buf[32];
|
||||||
int buf_size;
|
int buf_size;
|
||||||
|
bool bv;
|
||||||
u32 *val = file->private_data;
|
u32 *val = file->private_data;
|
||||||
|
|
||||||
buf_size = min(count, (sizeof(buf)-1));
|
buf_size = min(count, (sizeof(buf)-1));
|
||||||
if (copy_from_user(buf, user_buf, buf_size))
|
if (copy_from_user(buf, user_buf, buf_size))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
switch (buf[0]) {
|
if (strtobool(buf, &bv) == 0)
|
||||||
case 'y':
|
*val = bv;
|
||||||
case 'Y':
|
|
||||||
case '1':
|
|
||||||
*val = 1;
|
|
||||||
break;
|
|
||||||
case 'n':
|
|
||||||
case 'N':
|
|
||||||
case '0':
|
|
||||||
*val = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
@@ -274,70 +274,70 @@
|
|||||||
/* Kernel symbol table: Normal symbols */ \
|
/* Kernel symbol table: Normal symbols */ \
|
||||||
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
|
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___ksymtab) = .; \
|
VMLINUX_SYMBOL(__start___ksymtab) = .; \
|
||||||
*(__ksymtab) \
|
*(SORT(___ksymtab+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___ksymtab) = .; \
|
VMLINUX_SYMBOL(__stop___ksymtab) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: GPL-only symbols */ \
|
/* Kernel symbol table: GPL-only symbols */ \
|
||||||
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
|
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \
|
VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \
|
||||||
*(__ksymtab_gpl) \
|
*(SORT(___ksymtab_gpl+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
|
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: Normal unused symbols */ \
|
/* Kernel symbol table: Normal unused symbols */ \
|
||||||
__ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \
|
__ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \
|
VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \
|
||||||
*(__ksymtab_unused) \
|
*(SORT(___ksymtab_unused+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \
|
VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: GPL-only unused symbols */ \
|
/* Kernel symbol table: GPL-only unused symbols */ \
|
||||||
__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
|
__ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \
|
VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \
|
||||||
*(__ksymtab_unused_gpl) \
|
*(SORT(___ksymtab_unused_gpl+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \
|
VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: GPL-future-only symbols */ \
|
/* Kernel symbol table: GPL-future-only symbols */ \
|
||||||
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
|
__ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
|
VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \
|
||||||
*(__ksymtab_gpl_future) \
|
*(SORT(___ksymtab_gpl_future+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \
|
VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: Normal symbols */ \
|
/* Kernel symbol table: Normal symbols */ \
|
||||||
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
|
__kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___kcrctab) = .; \
|
VMLINUX_SYMBOL(__start___kcrctab) = .; \
|
||||||
*(__kcrctab) \
|
*(SORT(___kcrctab+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___kcrctab) = .; \
|
VMLINUX_SYMBOL(__stop___kcrctab) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: GPL-only symbols */ \
|
/* Kernel symbol table: GPL-only symbols */ \
|
||||||
__kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
|
__kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \
|
VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \
|
||||||
*(__kcrctab_gpl) \
|
*(SORT(___kcrctab_gpl+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
|
VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: Normal unused symbols */ \
|
/* Kernel symbol table: Normal unused symbols */ \
|
||||||
__kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \
|
__kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \
|
VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \
|
||||||
*(__kcrctab_unused) \
|
*(SORT(___kcrctab_unused+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \
|
VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: GPL-only unused symbols */ \
|
/* Kernel symbol table: GPL-only unused symbols */ \
|
||||||
__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
|
__kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \
|
VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \
|
||||||
*(__kcrctab_unused_gpl) \
|
*(SORT(___kcrctab_unused_gpl+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \
|
VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
/* Kernel symbol table: GPL-future-only symbols */ \
|
/* Kernel symbol table: GPL-future-only symbols */ \
|
||||||
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
|
__kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \
|
||||||
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
|
VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \
|
||||||
*(__kcrctab_gpl_future) \
|
*(SORT(___kcrctab_gpl_future+*)) \
|
||||||
VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
|
VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
9
include/linux/bsearch.h
Normal file
9
include/linux/bsearch.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _LINUX_BSEARCH_H
|
||||||
|
#define _LINUX_BSEARCH_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
void *bsearch(const void *key, const void *base, size_t num, size_t size,
|
||||||
|
int (*cmp)(const void *key, const void *elt));
|
||||||
|
|
||||||
|
#endif /* _LINUX_BSEARCH_H */
|
@@ -64,6 +64,9 @@ struct module_version_attribute {
|
|||||||
const char *version;
|
const char *version;
|
||||||
} __attribute__ ((__aligned__(sizeof(void *))));
|
} __attribute__ ((__aligned__(sizeof(void *))));
|
||||||
|
|
||||||
|
extern ssize_t __modver_version_show(struct module_attribute *,
|
||||||
|
struct module *, char *);
|
||||||
|
|
||||||
struct module_kobject
|
struct module_kobject
|
||||||
{
|
{
|
||||||
struct kobject kobj;
|
struct kobject kobj;
|
||||||
@@ -172,12 +175,7 @@ extern struct module __this_module;
|
|||||||
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
|
#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
|
||||||
#else
|
#else
|
||||||
#define MODULE_VERSION(_version) \
|
#define MODULE_VERSION(_version) \
|
||||||
extern ssize_t __modver_version_show(struct module_attribute *, \
|
static struct module_version_attribute ___modver_attr = { \
|
||||||
struct module *, char *); \
|
|
||||||
static struct module_version_attribute __modver_version_attr \
|
|
||||||
__used \
|
|
||||||
__attribute__ ((__section__ ("__modver"),aligned(sizeof(void *)))) \
|
|
||||||
= { \
|
|
||||||
.mattr = { \
|
.mattr = { \
|
||||||
.attr = { \
|
.attr = { \
|
||||||
.name = "version", \
|
.name = "version", \
|
||||||
@@ -187,7 +185,10 @@ extern struct module __this_module;
|
|||||||
}, \
|
}, \
|
||||||
.module_name = KBUILD_MODNAME, \
|
.module_name = KBUILD_MODNAME, \
|
||||||
.version = _version, \
|
.version = _version, \
|
||||||
}
|
}; \
|
||||||
|
static const struct module_version_attribute \
|
||||||
|
__used __attribute__ ((__section__ ("__modver"))) \
|
||||||
|
* __moduleparam_const __modver_attr = &___modver_attr
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Optional firmware file (or files) needed by the module
|
/* Optional firmware file (or files) needed by the module
|
||||||
@@ -223,7 +224,7 @@ struct module_use {
|
|||||||
extern void *__crc_##sym __attribute__((weak)); \
|
extern void *__crc_##sym __attribute__((weak)); \
|
||||||
static const unsigned long __kcrctab_##sym \
|
static const unsigned long __kcrctab_##sym \
|
||||||
__used \
|
__used \
|
||||||
__attribute__((section("__kcrctab" sec), unused)) \
|
__attribute__((section("___kcrctab" sec "+" #sym), unused)) \
|
||||||
= (unsigned long) &__crc_##sym;
|
= (unsigned long) &__crc_##sym;
|
||||||
#else
|
#else
|
||||||
#define __CRC_SYMBOL(sym, sec)
|
#define __CRC_SYMBOL(sym, sec)
|
||||||
@@ -238,7 +239,7 @@ struct module_use {
|
|||||||
= MODULE_SYMBOL_PREFIX #sym; \
|
= MODULE_SYMBOL_PREFIX #sym; \
|
||||||
static const struct kernel_symbol __ksymtab_##sym \
|
static const struct kernel_symbol __ksymtab_##sym \
|
||||||
__used \
|
__used \
|
||||||
__attribute__((section("__ksymtab" sec), unused)) \
|
__attribute__((section("___ksymtab" sec "+" #sym), unused)) \
|
||||||
= { (unsigned long)&sym, __kstrtab_##sym }
|
= { (unsigned long)&sym, __kstrtab_##sym }
|
||||||
|
|
||||||
#define EXPORT_SYMBOL(sym) \
|
#define EXPORT_SYMBOL(sym) \
|
||||||
@@ -367,34 +368,35 @@ struct module
|
|||||||
struct module_notes_attrs *notes_attrs;
|
struct module_notes_attrs *notes_attrs;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* The command line arguments (may be mangled). People like
|
||||||
|
keeping pointers to this stuff */
|
||||||
|
char *args;
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
/* Per-cpu data. */
|
/* Per-cpu data. */
|
||||||
void __percpu *percpu;
|
void __percpu *percpu;
|
||||||
unsigned int percpu_size;
|
unsigned int percpu_size;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The command line arguments (may be mangled). People like
|
|
||||||
keeping pointers to this stuff */
|
|
||||||
char *args;
|
|
||||||
#ifdef CONFIG_TRACEPOINTS
|
#ifdef CONFIG_TRACEPOINTS
|
||||||
struct tracepoint * const *tracepoints_ptrs;
|
|
||||||
unsigned int num_tracepoints;
|
unsigned int num_tracepoints;
|
||||||
|
struct tracepoint * const *tracepoints_ptrs;
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_JUMP_LABEL
|
#ifdef HAVE_JUMP_LABEL
|
||||||
struct jump_entry *jump_entries;
|
struct jump_entry *jump_entries;
|
||||||
unsigned int num_jump_entries;
|
unsigned int num_jump_entries;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_TRACING
|
#ifdef CONFIG_TRACING
|
||||||
const char **trace_bprintk_fmt_start;
|
|
||||||
unsigned int num_trace_bprintk_fmt;
|
unsigned int num_trace_bprintk_fmt;
|
||||||
|
const char **trace_bprintk_fmt_start;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_EVENT_TRACING
|
#ifdef CONFIG_EVENT_TRACING
|
||||||
struct ftrace_event_call **trace_events;
|
struct ftrace_event_call **trace_events;
|
||||||
unsigned int num_trace_events;
|
unsigned int num_trace_events;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
||||||
unsigned long *ftrace_callsites;
|
|
||||||
unsigned int num_ftrace_callsites;
|
unsigned int num_ftrace_callsites;
|
||||||
|
unsigned long *ftrace_callsites;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_MODULE_UNLOAD
|
#ifdef CONFIG_MODULE_UNLOAD
|
||||||
@@ -475,8 +477,9 @@ const struct kernel_symbol *find_symbol(const char *name,
|
|||||||
bool warn);
|
bool warn);
|
||||||
|
|
||||||
/* Walk the exported symbol table */
|
/* Walk the exported symbol table */
|
||||||
bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
|
bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
|
||||||
unsigned int symnum, void *data), void *data);
|
struct module *owner,
|
||||||
|
void *data), void *data);
|
||||||
|
|
||||||
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
|
/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if
|
||||||
symnum out of range. */
|
symnum out of range. */
|
||||||
|
@@ -67,9 +67,9 @@ struct kparam_string {
|
|||||||
struct kparam_array
|
struct kparam_array
|
||||||
{
|
{
|
||||||
unsigned int max;
|
unsigned int max;
|
||||||
|
unsigned int elemsize;
|
||||||
unsigned int *num;
|
unsigned int *num;
|
||||||
const struct kernel_param_ops *ops;
|
const struct kernel_param_ops *ops;
|
||||||
unsigned int elemsize;
|
|
||||||
void *elem;
|
void *elem;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -371,8 +371,9 @@ extern int param_get_invbool(char *buffer, const struct kernel_param *kp);
|
|||||||
*/
|
*/
|
||||||
#define module_param_array_named(name, array, type, nump, perm) \
|
#define module_param_array_named(name, array, type, nump, perm) \
|
||||||
static const struct kparam_array __param_arr_##name \
|
static const struct kparam_array __param_arr_##name \
|
||||||
= { ARRAY_SIZE(array), nump, ¶m_ops_##type, \
|
= { .max = ARRAY_SIZE(array), .num = nump, \
|
||||||
sizeof(array[0]), array }; \
|
.ops = ¶m_ops_##type, \
|
||||||
|
.elemsize = sizeof(array[0]), .elem = array }; \
|
||||||
__module_param_call(MODULE_PARAM_PREFIX, name, \
|
__module_param_call(MODULE_PARAM_PREFIX, name, \
|
||||||
¶m_array_ops, \
|
¶m_array_ops, \
|
||||||
.arr = &__param_arr_##name, \
|
.arr = &__param_arr_##name, \
|
||||||
|
@@ -123,6 +123,7 @@ extern char **argv_split(gfp_t gfp, const char *str, int *argcp);
|
|||||||
extern void argv_free(char **argv);
|
extern void argv_free(char **argv);
|
||||||
|
|
||||||
extern bool sysfs_streq(const char *s1, const char *s2);
|
extern bool sysfs_streq(const char *s1, const char *s2);
|
||||||
|
extern int strtobool(const char *s, bool *res);
|
||||||
|
|
||||||
#ifdef CONFIG_BINARY_PRINTF
|
#ifdef CONFIG_BINARY_PRINTF
|
||||||
int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
|
int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args);
|
||||||
|
@@ -57,6 +57,7 @@
|
|||||||
#include <linux/kmemleak.h>
|
#include <linux/kmemleak.h>
|
||||||
#include <linux/jump_label.h>
|
#include <linux/jump_label.h>
|
||||||
#include <linux/pfn.h>
|
#include <linux/pfn.h>
|
||||||
|
#include <linux/bsearch.h>
|
||||||
|
|
||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
#include <trace/events/module.h>
|
#include <trace/events/module.h>
|
||||||
@@ -240,14 +241,13 @@ static bool each_symbol_in_section(const struct symsearch *arr,
|
|||||||
struct module *owner,
|
struct module *owner,
|
||||||
bool (*fn)(const struct symsearch *syms,
|
bool (*fn)(const struct symsearch *syms,
|
||||||
struct module *owner,
|
struct module *owner,
|
||||||
unsigned int symnum, void *data),
|
void *data),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
unsigned int i, j;
|
unsigned int j;
|
||||||
|
|
||||||
for (j = 0; j < arrsize; j++) {
|
for (j = 0; j < arrsize; j++) {
|
||||||
for (i = 0; i < arr[j].stop - arr[j].start; i++)
|
if (fn(&arr[j], owner, data))
|
||||||
if (fn(&arr[j], owner, i, data))
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,8 +255,10 @@ static bool each_symbol_in_section(const struct symsearch *arr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Returns true as soon as fn returns true, otherwise false. */
|
/* Returns true as soon as fn returns true, otherwise false. */
|
||||||
bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
|
bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
|
||||||
unsigned int symnum, void *data), void *data)
|
struct module *owner,
|
||||||
|
void *data),
|
||||||
|
void *data)
|
||||||
{
|
{
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
static const struct symsearch arr[] = {
|
static const struct symsearch arr[] = {
|
||||||
@@ -309,7 +311,7 @@ bool each_symbol(bool (*fn)(const struct symsearch *arr, struct module *owner,
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(each_symbol);
|
EXPORT_SYMBOL_GPL(each_symbol_section);
|
||||||
|
|
||||||
struct find_symbol_arg {
|
struct find_symbol_arg {
|
||||||
/* Input */
|
/* Input */
|
||||||
@@ -323,15 +325,12 @@ struct find_symbol_arg {
|
|||||||
const struct kernel_symbol *sym;
|
const struct kernel_symbol *sym;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool find_symbol_in_section(const struct symsearch *syms,
|
static bool check_symbol(const struct symsearch *syms,
|
||||||
struct module *owner,
|
struct module *owner,
|
||||||
unsigned int symnum, void *data)
|
unsigned int symnum, void *data)
|
||||||
{
|
{
|
||||||
struct find_symbol_arg *fsa = data;
|
struct find_symbol_arg *fsa = data;
|
||||||
|
|
||||||
if (strcmp(syms->start[symnum].name, fsa->name) != 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!fsa->gplok) {
|
if (!fsa->gplok) {
|
||||||
if (syms->licence == GPL_ONLY)
|
if (syms->licence == GPL_ONLY)
|
||||||
return false;
|
return false;
|
||||||
@@ -365,6 +364,30 @@ static bool find_symbol_in_section(const struct symsearch *syms,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmp_name(const void *va, const void *vb)
|
||||||
|
{
|
||||||
|
const char *a;
|
||||||
|
const struct kernel_symbol *b;
|
||||||
|
a = va; b = vb;
|
||||||
|
return strcmp(a, b->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool find_symbol_in_section(const struct symsearch *syms,
|
||||||
|
struct module *owner,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct find_symbol_arg *fsa = data;
|
||||||
|
struct kernel_symbol *sym;
|
||||||
|
|
||||||
|
sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
|
||||||
|
sizeof(struct kernel_symbol), cmp_name);
|
||||||
|
|
||||||
|
if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Find a symbol and return it, along with, (optional) crc and
|
/* Find a symbol and return it, along with, (optional) crc and
|
||||||
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
|
* (optional) module which owns it. Needs preempt disabled or module_mutex. */
|
||||||
const struct kernel_symbol *find_symbol(const char *name,
|
const struct kernel_symbol *find_symbol(const char *name,
|
||||||
@@ -379,7 +402,7 @@ const struct kernel_symbol *find_symbol(const char *name,
|
|||||||
fsa.gplok = gplok;
|
fsa.gplok = gplok;
|
||||||
fsa.warn = warn;
|
fsa.warn = warn;
|
||||||
|
|
||||||
if (each_symbol(find_symbol_in_section, &fsa)) {
|
if (each_symbol_section(find_symbol_in_section, &fsa)) {
|
||||||
if (owner)
|
if (owner)
|
||||||
*owner = fsa.owner;
|
*owner = fsa.owner;
|
||||||
if (crc)
|
if (crc)
|
||||||
@@ -1607,27 +1630,28 @@ static void set_section_ro_nx(void *base,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setting memory back to RW+NX before releasing it */
|
static void unset_module_core_ro_nx(struct module *mod)
|
||||||
void unset_section_ro_nx(struct module *mod, void *module_region)
|
|
||||||
{
|
{
|
||||||
unsigned long total_pages;
|
set_page_attributes(mod->module_core + mod->core_text_size,
|
||||||
|
mod->module_core + mod->core_size,
|
||||||
if (mod->module_core == module_region) {
|
set_memory_x);
|
||||||
/* Set core as NX+RW */
|
set_page_attributes(mod->module_core,
|
||||||
total_pages = MOD_NUMBER_OF_PAGES(mod->module_core, mod->core_size);
|
mod->module_core + mod->core_ro_size,
|
||||||
set_memory_nx((unsigned long)mod->module_core, total_pages);
|
set_memory_rw);
|
||||||
set_memory_rw((unsigned long)mod->module_core, total_pages);
|
|
||||||
|
|
||||||
} else if (mod->module_init == module_region) {
|
|
||||||
/* Set init as NX+RW */
|
|
||||||
total_pages = MOD_NUMBER_OF_PAGES(mod->module_init, mod->init_size);
|
|
||||||
set_memory_nx((unsigned long)mod->module_init, total_pages);
|
|
||||||
set_memory_rw((unsigned long)mod->module_init, total_pages);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void unset_module_init_ro_nx(struct module *mod)
|
||||||
|
{
|
||||||
|
set_page_attributes(mod->module_init + mod->init_text_size,
|
||||||
|
mod->module_init + mod->init_size,
|
||||||
|
set_memory_x);
|
||||||
|
set_page_attributes(mod->module_init,
|
||||||
|
mod->module_init + mod->init_ro_size,
|
||||||
|
set_memory_rw);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate through all modules and set each module's text as RW */
|
/* Iterate through all modules and set each module's text as RW */
|
||||||
void set_all_modules_text_rw()
|
void set_all_modules_text_rw(void)
|
||||||
{
|
{
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
@@ -1648,7 +1672,7 @@ void set_all_modules_text_rw()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate through all modules and set each module's text as RO */
|
/* Iterate through all modules and set each module's text as RO */
|
||||||
void set_all_modules_text_ro()
|
void set_all_modules_text_ro(void)
|
||||||
{
|
{
|
||||||
struct module *mod;
|
struct module *mod;
|
||||||
|
|
||||||
@@ -1669,7 +1693,8 @@ void set_all_modules_text_ro()
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
|
static inline void set_section_ro_nx(void *base, unsigned long text_size, unsigned long ro_size, unsigned long total_size) { }
|
||||||
static inline void unset_section_ro_nx(struct module *mod, void *module_region) { }
|
static void unset_module_core_ro_nx(struct module *mod) { }
|
||||||
|
static void unset_module_init_ro_nx(struct module *mod) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Free a module, remove from lists, etc. */
|
/* Free a module, remove from lists, etc. */
|
||||||
@@ -1696,7 +1721,7 @@ static void free_module(struct module *mod)
|
|||||||
destroy_params(mod->kp, mod->num_kp);
|
destroy_params(mod->kp, mod->num_kp);
|
||||||
|
|
||||||
/* This may be NULL, but that's OK */
|
/* This may be NULL, but that's OK */
|
||||||
unset_section_ro_nx(mod, mod->module_init);
|
unset_module_init_ro_nx(mod);
|
||||||
module_free(mod, mod->module_init);
|
module_free(mod, mod->module_init);
|
||||||
kfree(mod->args);
|
kfree(mod->args);
|
||||||
percpu_modfree(mod);
|
percpu_modfree(mod);
|
||||||
@@ -1705,7 +1730,7 @@ static void free_module(struct module *mod)
|
|||||||
lockdep_free_key_range(mod->module_core, mod->core_size);
|
lockdep_free_key_range(mod->module_core, mod->core_size);
|
||||||
|
|
||||||
/* Finally, free the core (containing the module structure) */
|
/* Finally, free the core (containing the module structure) */
|
||||||
unset_section_ro_nx(mod, mod->module_core);
|
unset_module_core_ro_nx(mod);
|
||||||
module_free(mod, mod->module_core);
|
module_free(mod, mod->module_core);
|
||||||
|
|
||||||
#ifdef CONFIG_MPU
|
#ifdef CONFIG_MPU
|
||||||
@@ -2030,11 +2055,8 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
|
|||||||
const struct kernel_symbol *start,
|
const struct kernel_symbol *start,
|
||||||
const struct kernel_symbol *stop)
|
const struct kernel_symbol *stop)
|
||||||
{
|
{
|
||||||
const struct kernel_symbol *ks = start;
|
return bsearch(name, start, stop - start,
|
||||||
for (; ks < stop; ks++)
|
sizeof(struct kernel_symbol), cmp_name);
|
||||||
if (strcmp(ks->name, name) == 0)
|
|
||||||
return ks;
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_exported(const char *name, unsigned long value,
|
static int is_exported(const char *name, unsigned long value,
|
||||||
@@ -2931,10 +2953,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
|||||||
mod->symtab = mod->core_symtab;
|
mod->symtab = mod->core_symtab;
|
||||||
mod->strtab = mod->core_strtab;
|
mod->strtab = mod->core_strtab;
|
||||||
#endif
|
#endif
|
||||||
unset_section_ro_nx(mod, mod->module_init);
|
unset_module_init_ro_nx(mod);
|
||||||
module_free(mod, mod->module_init);
|
module_free(mod, mod->module_init);
|
||||||
mod->module_init = NULL;
|
mod->module_init = NULL;
|
||||||
mod->init_size = 0;
|
mod->init_size = 0;
|
||||||
|
mod->init_ro_size = 0;
|
||||||
mod->init_text_size = 0;
|
mod->init_text_size = 0;
|
||||||
mutex_unlock(&module_mutex);
|
mutex_unlock(&module_mutex);
|
||||||
|
|
||||||
|
@@ -297,21 +297,15 @@ EXPORT_SYMBOL(param_ops_charp);
|
|||||||
int param_set_bool(const char *val, const struct kernel_param *kp)
|
int param_set_bool(const char *val, const struct kernel_param *kp)
|
||||||
{
|
{
|
||||||
bool v;
|
bool v;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/* No equals means "set"... */
|
/* No equals means "set"... */
|
||||||
if (!val) val = "1";
|
if (!val) val = "1";
|
||||||
|
|
||||||
/* One of =[yYnN01] */
|
/* One of =[yYnN01] */
|
||||||
switch (val[0]) {
|
ret = strtobool(val, &v);
|
||||||
case 'y': case 'Y': case '1':
|
if (ret)
|
||||||
v = true;
|
return ret;
|
||||||
break;
|
|
||||||
case 'n': case 'N': case '0':
|
|
||||||
v = false;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kp->flags & KPARAM_ISBOOL)
|
if (kp->flags & KPARAM_ISBOOL)
|
||||||
*(bool *)kp->arg = v;
|
*(bool *)kp->arg = v;
|
||||||
@@ -821,15 +815,18 @@ ssize_t __modver_version_show(struct module_attribute *mattr,
|
|||||||
return sprintf(buf, "%s\n", vattr->version);
|
return sprintf(buf, "%s\n", vattr->version);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct module_version_attribute __start___modver[], __stop___modver[];
|
extern const struct module_version_attribute *__start___modver[];
|
||||||
|
extern const struct module_version_attribute *__stop___modver[];
|
||||||
|
|
||||||
static void __init version_sysfs_builtin(void)
|
static void __init version_sysfs_builtin(void)
|
||||||
{
|
{
|
||||||
const struct module_version_attribute *vattr;
|
const struct module_version_attribute **p;
|
||||||
struct module_kobject *mk;
|
struct module_kobject *mk;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
for (vattr = __start___modver; vattr < __stop___modver; vattr++) {
|
for (p = __start___modver; p < __stop___modver; p++) {
|
||||||
|
const struct module_version_attribute *vattr = *p;
|
||||||
|
|
||||||
mk = locate_module_kobject(vattr->module_name);
|
mk = locate_module_kobject(vattr->module_name);
|
||||||
if (mk) {
|
if (mk) {
|
||||||
err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
|
err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr);
|
||||||
|
@@ -21,7 +21,8 @@ lib-y += kobject.o kref.o klist.o
|
|||||||
|
|
||||||
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
|
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
|
||||||
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
|
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
|
||||||
string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o
|
string_helpers.o gcd.o lcm.o list_sort.o uuid.o flex_array.o \
|
||||||
|
bsearch.o
|
||||||
obj-y += kstrtox.o
|
obj-y += kstrtox.o
|
||||||
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
|
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
|
||||||
|
|
||||||
|
53
lib/bsearch.c
Normal file
53
lib/bsearch.c
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* A generic implementation of binary search for the Linux kernel
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008-2009 Ksplice, Inc.
|
||||||
|
* Author: Tim Abbott <tabbott@ksplice.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation; version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/bsearch.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bsearch - binary search an array of elements
|
||||||
|
* @key: pointer to item being searched for
|
||||||
|
* @base: pointer to first element to search
|
||||||
|
* @num: number of elements
|
||||||
|
* @size: size of each element
|
||||||
|
* @cmp: pointer to comparison function
|
||||||
|
*
|
||||||
|
* This function does a binary search on the given array. The
|
||||||
|
* contents of the array should already be in ascending sorted order
|
||||||
|
* under the provided comparison function.
|
||||||
|
*
|
||||||
|
* Note that the key need not have the same type as the elements in
|
||||||
|
* the array, e.g. key could be a string and the comparison function
|
||||||
|
* could compare the string with the struct's name field. However, if
|
||||||
|
* the key and elements in the array are of the same type, you can use
|
||||||
|
* the same comparison function for both sort() and bsearch().
|
||||||
|
*/
|
||||||
|
void *bsearch(const void *key, const void *base, size_t num, size_t size,
|
||||||
|
int (*cmp)(const void *key, const void *elt))
|
||||||
|
{
|
||||||
|
size_t start = 0, end = num;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
while (start < end) {
|
||||||
|
size_t mid = start + (end - start) / 2;
|
||||||
|
|
||||||
|
result = cmp(key, base + mid * size);
|
||||||
|
if (result < 0)
|
||||||
|
end = mid;
|
||||||
|
else if (result > 0)
|
||||||
|
start = mid + 1;
|
||||||
|
else
|
||||||
|
return (void *)base + mid * size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(bsearch);
|
29
lib/string.c
29
lib/string.c
@@ -535,6 +535,35 @@ bool sysfs_streq(const char *s1, const char *s2)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sysfs_streq);
|
EXPORT_SYMBOL(sysfs_streq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* strtobool - convert common user inputs into boolean values
|
||||||
|
* @s: input string
|
||||||
|
* @res: result
|
||||||
|
*
|
||||||
|
* This routine returns 0 iff the first character is one of 'Yy1Nn0'.
|
||||||
|
* Otherwise it will return -EINVAL. Value pointed to by res is
|
||||||
|
* updated upon finding a match.
|
||||||
|
*/
|
||||||
|
int strtobool(const char *s, bool *res)
|
||||||
|
{
|
||||||
|
switch (s[0]) {
|
||||||
|
case 'y':
|
||||||
|
case 'Y':
|
||||||
|
case '1':
|
||||||
|
*res = true;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
case 'N':
|
||||||
|
case '0':
|
||||||
|
*res = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(strtobool);
|
||||||
|
|
||||||
#ifndef __HAVE_ARCH_MEMSET
|
#ifndef __HAVE_ARCH_MEMSET
|
||||||
/**
|
/**
|
||||||
* memset - Fill a region of memory with the given value
|
* memset - Fill a region of memory with the given value
|
||||||
|
@@ -420,11 +420,10 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hdr->e_shnum == 0) {
|
if (hdr->e_shnum == SHN_UNDEF) {
|
||||||
/*
|
/*
|
||||||
* There are more than 64k sections,
|
* There are more than 64k sections,
|
||||||
* read count from .sh_size.
|
* read count from .sh_size.
|
||||||
* note: it doesn't need shndx2secindex()
|
|
||||||
*/
|
*/
|
||||||
info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
|
info->num_sections = TO_NATIVE(sechdrs[0].sh_size);
|
||||||
}
|
}
|
||||||
@@ -432,8 +431,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||||||
info->num_sections = hdr->e_shnum;
|
info->num_sections = hdr->e_shnum;
|
||||||
}
|
}
|
||||||
if (hdr->e_shstrndx == SHN_XINDEX) {
|
if (hdr->e_shstrndx == SHN_XINDEX) {
|
||||||
info->secindex_strings =
|
info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link);
|
||||||
shndx2secindex(TO_NATIVE(sechdrs[0].sh_link));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
info->secindex_strings = hdr->e_shstrndx;
|
info->secindex_strings = hdr->e_shstrndx;
|
||||||
@@ -489,7 +487,7 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||||||
sechdrs[i].sh_offset;
|
sechdrs[i].sh_offset;
|
||||||
info->symtab_stop = (void *)hdr +
|
info->symtab_stop = (void *)hdr +
|
||||||
sechdrs[i].sh_offset + sechdrs[i].sh_size;
|
sechdrs[i].sh_offset + sechdrs[i].sh_size;
|
||||||
sh_link_idx = shndx2secindex(sechdrs[i].sh_link);
|
sh_link_idx = sechdrs[i].sh_link;
|
||||||
info->strtab = (void *)hdr +
|
info->strtab = (void *)hdr +
|
||||||
sechdrs[sh_link_idx].sh_offset;
|
sechdrs[sh_link_idx].sh_offset;
|
||||||
}
|
}
|
||||||
@@ -516,11 +514,9 @@ static int parse_elf(struct elf_info *info, const char *filename)
|
|||||||
|
|
||||||
if (symtab_shndx_idx != ~0U) {
|
if (symtab_shndx_idx != ~0U) {
|
||||||
Elf32_Word *p;
|
Elf32_Word *p;
|
||||||
if (symtab_idx !=
|
if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link)
|
||||||
shndx2secindex(sechdrs[symtab_shndx_idx].sh_link))
|
|
||||||
fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
|
fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n",
|
||||||
filename,
|
filename, sechdrs[symtab_shndx_idx].sh_link,
|
||||||
shndx2secindex(sechdrs[symtab_shndx_idx].sh_link),
|
|
||||||
symtab_idx);
|
symtab_idx);
|
||||||
/* Fix endianness */
|
/* Fix endianness */
|
||||||
for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
|
for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop;
|
||||||
@@ -1446,7 +1442,7 @@ static unsigned int *reloc_location(struct elf_info *elf,
|
|||||||
Elf_Shdr *sechdr, Elf_Rela *r)
|
Elf_Shdr *sechdr, Elf_Rela *r)
|
||||||
{
|
{
|
||||||
Elf_Shdr *sechdrs = elf->sechdrs;
|
Elf_Shdr *sechdrs = elf->sechdrs;
|
||||||
int section = shndx2secindex(sechdr->sh_info);
|
int section = sechdr->sh_info;
|
||||||
|
|
||||||
return (void *)elf->hdr + sechdrs[section].sh_offset +
|
return (void *)elf->hdr + sechdrs[section].sh_offset +
|
||||||
r->r_offset;
|
r->r_offset;
|
||||||
|
@@ -145,33 +145,22 @@ static inline int is_shndx_special(unsigned int i)
|
|||||||
return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
|
return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* shndx is in [0..SHN_LORESERVE) U (SHN_HIRESERVE, 0xfffffff], thus:
|
/*
|
||||||
* shndx == 0 <=> sechdrs[0]
|
* Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of
|
||||||
* ......
|
* the way to -256..-1, to avoid conflicting with real section
|
||||||
* shndx == SHN_LORESERVE-1 <=> sechdrs[SHN_LORESERVE-1]
|
* indices.
|
||||||
* shndx == SHN_HIRESERVE+1 <=> sechdrs[SHN_LORESERVE]
|
|
||||||
* shndx == SHN_HIRESERVE+2 <=> sechdrs[SHN_LORESERVE+1]
|
|
||||||
* ......
|
|
||||||
* fyi: sym->st_shndx is uint16, SHN_LORESERVE = ff00, SHN_HIRESERVE = ffff,
|
|
||||||
* so basically we map 0000..feff -> 0000..feff
|
|
||||||
* ff00..ffff -> (you are a bad boy, dont do it)
|
|
||||||
* 10000..xxxx -> ff00..(xxxx-0x100)
|
|
||||||
*/
|
*/
|
||||||
static inline unsigned int shndx2secindex(unsigned int i)
|
#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1))
|
||||||
{
|
|
||||||
if (i <= SHN_HIRESERVE)
|
|
||||||
return i;
|
|
||||||
return i - (SHN_HIRESERVE + 1 - SHN_LORESERVE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
|
/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */
|
||||||
static inline unsigned int get_secindex(const struct elf_info *info,
|
static inline unsigned int get_secindex(const struct elf_info *info,
|
||||||
const Elf_Sym *sym)
|
const Elf_Sym *sym)
|
||||||
{
|
{
|
||||||
|
if (is_shndx_special(sym->st_shndx))
|
||||||
|
return SPECIAL(sym->st_shndx);
|
||||||
if (sym->st_shndx != SHN_XINDEX)
|
if (sym->st_shndx != SHN_XINDEX)
|
||||||
return sym->st_shndx;
|
return sym->st_shndx;
|
||||||
return shndx2secindex(info->symtab_shndx_start[sym -
|
return info->symtab_shndx_start[sym - info->symtab_start];
|
||||||
info->symtab_start]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* file2alias.c */
|
/* file2alias.c */
|
||||||
|
@@ -5,4 +5,15 @@
|
|||||||
*/
|
*/
|
||||||
SECTIONS {
|
SECTIONS {
|
||||||
/DISCARD/ : { *(.discard) }
|
/DISCARD/ : { *(.discard) }
|
||||||
|
|
||||||
|
__ksymtab : { *(SORT(___ksymtab+*)) }
|
||||||
|
__ksymtab_gpl : { *(SORT(___ksymtab_gpl+*)) }
|
||||||
|
__ksymtab_unused : { *(SORT(___ksymtab_unused+*)) }
|
||||||
|
__ksymtab_unused_gpl : { *(SORT(___ksymtab_unused_gpl+*)) }
|
||||||
|
__ksymtab_gpl_future : { *(SORT(___ksymtab_gpl_future+*)) }
|
||||||
|
__kcrctab : { *(SORT(___kcrctab+*)) }
|
||||||
|
__kcrctab_gpl : { *(SORT(___kcrctab_gpl+*)) }
|
||||||
|
__kcrctab_unused : { *(SORT(___kcrctab_unused+*)) }
|
||||||
|
__kcrctab_unused_gpl : { *(SORT(___kcrctab_unused_gpl+*)) }
|
||||||
|
__kcrctab_gpl_future : { *(SORT(___kcrctab_gpl_future+*)) }
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user