mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
[XEN] Make labels _start,_end,_stext,_etext,_sinittext,_einittext generic.
Also sync the tools/symbol.c symbol table generator with Linux. Make section names generic (e.e.g, .init.text, .init.data, ...). Signed-off-by: Keir Fraser <keir@xensource.com>
This commit is contained in:
1 parent
0550678b74
commit
72c07f4138
18 files changed
+178
-484
No files matched your search
@@ -56,26 +56,6 @@ is_platform_hp_ski(void)
|
||||
|
||||
struct pt_regs *guest_cpu_user_regs(void) { return vcpu_regs(current); }
|
||||
|
||||
///////////////////////////////
|
||||
// from arch/ia64/traps.c
|
||||
///////////////////////////////
|
||||
|
||||
int is_kernel_text(unsigned long addr)
|
||||
{
|
||||
extern char _stext[], _etext[];
|
||||
if (addr >= (unsigned long) _stext &&
|
||||
addr <= (unsigned long) _etext)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long kernel_text_end(void)
|
||||
{
|
||||
extern char _etext[];
|
||||
return (unsigned long) _etext;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// from common/keyhandler.c
|
||||
///////////////////////////////
|
||||
|
||||
@@ -91,19 +91,6 @@ static struct domain *idle_domain;
|
||||
|
||||
volatile struct processor_area * volatile global_cpu_table[NR_CPUS];
|
||||
|
||||
int is_kernel_text(unsigned long addr)
|
||||
{
|
||||
if (addr >= (unsigned long) &_start &&
|
||||
addr <= (unsigned long) &_etext)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned long kernel_text_end(void)
|
||||
{
|
||||
return (unsigned long) &_etext;
|
||||
}
|
||||
|
||||
static void __init do_initcalls(void)
|
||||
{
|
||||
initcall_t *call;
|
||||
|
||||
@@ -113,10 +113,10 @@ SECTIONS
|
||||
|
||||
. = ALIGN(32);
|
||||
__setup_start = .;
|
||||
.setup.init : { *(.setup.init) }
|
||||
.init.setup : { *(.init.setup) }
|
||||
__setup_end = .;
|
||||
__initcall_start = .;
|
||||
.initcall.init : { *(.initcall.init) }
|
||||
.initcall.init : { *(.initcall1.init) }
|
||||
__initcall_end = .;
|
||||
__inithcall_start = .;
|
||||
.inithcall.text : { *(.inithcall.text) }
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
.text
|
||||
|
||||
ENTRY(start)
|
||||
ENTRY(stext)
|
||||
ENTRY(_stext)
|
||||
jmp __start
|
||||
|
||||
.align 4
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#define SYM_PHYS(sym) (sym - __PAGE_OFFSET)
|
||||
|
||||
ENTRY(start)
|
||||
ENTRY(stext)
|
||||
ENTRY(_stext)
|
||||
jmp __start
|
||||
|
||||
.org 0x004
|
||||
|
||||
+2
-18
@@ -115,22 +115,6 @@ integer_param("debug_stack_lines", debug_stack_lines);
|
||||
#define ESP_BEFORE_EXCEPTION(regs) ((unsigned long *)regs->rsp)
|
||||
#endif
|
||||
|
||||
int is_kernel_text(unsigned long addr)
|
||||
{
|
||||
extern char _stext, _etext;
|
||||
if (addr >= (unsigned long) &_stext &&
|
||||
addr <= (unsigned long) &_etext)
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
unsigned long kernel_text_end(void)
|
||||
{
|
||||
extern char _etext;
|
||||
return (unsigned long) &_etext;
|
||||
}
|
||||
|
||||
static void show_guest_stack(struct cpu_user_regs *regs)
|
||||
{
|
||||
int i;
|
||||
@@ -187,7 +171,7 @@ static void show_trace(struct cpu_user_regs *regs)
|
||||
while ( ((long)stack & (STACK_SIZE-BYTES_PER_LONG)) != 0 )
|
||||
{
|
||||
addr = *stack++;
|
||||
if ( is_kernel_text(addr) )
|
||||
if ( is_kernel_text(addr) || is_kernel_inittext(addr) )
|
||||
{
|
||||
printk("[<%p>]", _p(addr));
|
||||
print_symbol(" %s\n ", addr);
|
||||
@@ -316,7 +300,7 @@ void show_stack_overflow(unsigned long esp)
|
||||
while ( ((long)stack & (STACK_SIZE-BYTES_PER_LONG)) != 0 )
|
||||
{
|
||||
addr = *stack++;
|
||||
if ( is_kernel_text(addr) )
|
||||
if ( is_kernel_text(addr) || is_kernel_inittext(addr) )
|
||||
{
|
||||
printk("%p: [<%p>]", stack, _p(addr));
|
||||
print_symbol(" %s\n ", addr);
|
||||
|
||||
@@ -19,7 +19,8 @@ PHDRS
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xFF000000 + 0x100000;
|
||||
_text = .; /* Text and read-only data */
|
||||
_start = .;
|
||||
_stext = .; /* Text and read-only data */
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.fixup)
|
||||
@@ -51,14 +52,16 @@ SECTIONS
|
||||
|
||||
. = ALIGN(4096); /* Init code and data */
|
||||
__init_begin = .;
|
||||
.text.init : { *(.text.init) } :text
|
||||
.data.init : { *(.data.init) } :text
|
||||
_sinittext = .;
|
||||
.init.text : { *(.init.text) } :text
|
||||
_einittext = .;
|
||||
.init.data : { *(.init.data) } :text
|
||||
. = ALIGN(32);
|
||||
__setup_start = .;
|
||||
.setup.init : { *(.setup.init) } :text
|
||||
.init.setup : { *(.init.setup) } :text
|
||||
__setup_end = .;
|
||||
__initcall_start = .;
|
||||
.initcall.init : { *(.initcall.init) } :text
|
||||
.initcall.init : { *(.initcall1.init) } :text
|
||||
__initcall_end = .;
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
__init_end = .;
|
||||
@@ -80,8 +83,8 @@ SECTIONS
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.text.exit)
|
||||
*(.data.exit)
|
||||
*(.exit.text)
|
||||
*(.exit.data)
|
||||
*(.exitcall.exit)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ PHDRS
|
||||
SECTIONS
|
||||
{
|
||||
. = 0xFFFF830000100000;
|
||||
_text = .; /* Text and read-only data */
|
||||
_start = .;
|
||||
_stext = .; /* Text and read-only data */
|
||||
.text : {
|
||||
*(.text)
|
||||
*(.fixup)
|
||||
@@ -49,14 +50,16 @@ SECTIONS
|
||||
|
||||
. = ALIGN(4096); /* Init code and data */
|
||||
__init_begin = .;
|
||||
.text.init : { *(.text.init) } :text
|
||||
.data.init : { *(.data.init) } :text
|
||||
_sinittext = .;
|
||||
.init.text : { *(.init.text) } :text
|
||||
_einittext = .;
|
||||
.init.data : { *(.init.data) } :text
|
||||
. = ALIGN(32);
|
||||
__setup_start = .;
|
||||
.setup.init : { *(.setup.init) } :text
|
||||
.init.setup : { *(.init.setup) } :text
|
||||
__setup_end = .;
|
||||
__initcall_start = .;
|
||||
.initcall.init : { *(.initcall.init) } :text
|
||||
.initcall.init : { *(.initcall1.init) } :text
|
||||
__initcall_end = .;
|
||||
. = ALIGN(PAGE_SIZE);
|
||||
__init_end = .;
|
||||
@@ -78,8 +81,8 @@ SECTIONS
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.text.exit)
|
||||
*(.data.exit)
|
||||
*(.exit.text)
|
||||
*(.exit.data)
|
||||
*(.exitcall.exit)
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -150,12 +150,10 @@ static int kexec_get_reserve(xen_kexec_range_t *range)
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern unsigned long _text;
|
||||
|
||||
static int kexec_get_xen(xen_kexec_range_t *range)
|
||||
{
|
||||
range->start = virt_to_maddr(&_text);
|
||||
range->size = (unsigned long)&_end - (unsigned long)&_text;
|
||||
range->start = virt_to_maddr(_start);
|
||||
range->size = (unsigned long)_end - (unsigned long)_start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <xen/config.h>
|
||||
#include <xen/symbols.h>
|
||||
#include <xen/kernel.h>
|
||||
#include <xen/init.h>
|
||||
#include <xen/lib.h>
|
||||
#include <xen/string.h>
|
||||
@@ -99,7 +100,7 @@ const char *symbols_lookup(unsigned long addr,
|
||||
namebuf[KSYM_NAME_LEN] = 0;
|
||||
namebuf[0] = 0;
|
||||
|
||||
if (!is_kernel_text(addr))
|
||||
if (!is_kernel_text(addr) && !is_kernel_inittext(addr))
|
||||
return NULL;
|
||||
|
||||
/* do a binary search on the sorted symbols_addresses array */
|
||||
@@ -130,7 +131,8 @@ const char *symbols_lookup(unsigned long addr,
|
||||
|
||||
/* if we found no next symbol, we use the end of the section */
|
||||
if (!symbol_end)
|
||||
symbol_end = kernel_text_end();
|
||||
symbol_end = is_kernel_inittext(addr) ?
|
||||
(unsigned long)_einittext : (unsigned long)_etext;
|
||||
|
||||
*symbolsize = symbol_end - symbols_addresses[low];
|
||||
*offset = addr - symbols_addresses[low];
|
||||
|
||||
@@ -1,29 +1,4 @@
|
||||
#ifndef _XEN_ASM_INIT_H
|
||||
#define _XEN_ASM_INIT_H
|
||||
|
||||
/*
|
||||
* Mark functions and data as being only used at initialization
|
||||
* or exit time.
|
||||
*/
|
||||
#define __init \
|
||||
__attribute__ ((__section__ (".init.text")))
|
||||
#define __exit \
|
||||
__attribute_used__ __attribute__ ((__section__(".text.exit")))
|
||||
#define __initdata \
|
||||
__attribute__ ((__section__ (".init.data")))
|
||||
#define __exitdata \
|
||||
__attribute_used__ __attribute__ ((__section__ (".data.exit")))
|
||||
#define __initsetup \
|
||||
__attribute_used__ __attribute__ ((__section__ (".init.setup")))
|
||||
#define __init_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".initcall1.init")))
|
||||
#define __exit_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
|
||||
|
||||
/* For assembly routines
|
||||
#define __INIT .section ".text.init","ax"
|
||||
#define __FINIT .previous
|
||||
#define __INITDATA .section ".data.init","aw"
|
||||
*/
|
||||
|
||||
#endif /* _XEN_ASM_INIT_H */
|
||||
@@ -21,25 +21,6 @@
|
||||
#ifndef _XEN_ASM_INIT_H
|
||||
#define _XEN_ASM_INIT_H
|
||||
|
||||
/*
|
||||
* Mark functions and data as being only used at initialization
|
||||
* or exit time.
|
||||
*/
|
||||
#define __init \
|
||||
__attribute__ ((__section__ (".init.text")))
|
||||
#define __exit \
|
||||
__attribute_used__ __attribute__ ((__section__(".text.exit")))
|
||||
#define __initdata \
|
||||
__attribute__ ((__section__ (".init.data")))
|
||||
#define __exitdata \
|
||||
__attribute_used__ __attribute__ ((__section__ (".data.exit")))
|
||||
#define __initsetup \
|
||||
__attribute_used__ __attribute__ ((__section__ (".setup.init")))
|
||||
#define __init_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".initcall.init")))
|
||||
#define __exit_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
|
||||
|
||||
struct cpu_user_regs;
|
||||
typedef void (*hcall_handler_t)(struct cpu_user_regs *regs);
|
||||
|
||||
|
||||
@@ -84,10 +84,6 @@
|
||||
|
||||
#define CONFIG_DMA_BITSIZE 30
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
extern unsigned long _end; /* standard ELF symbol */
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
#if defined(__x86_64__)
|
||||
|
||||
#define CONFIG_X86_64 1
|
||||
|
||||
@@ -1,29 +1,4 @@
|
||||
#ifndef _XEN_ASM_INIT_H
|
||||
#define _XEN_ASM_INIT_H
|
||||
|
||||
/*
|
||||
* Mark functions and data as being only used at initialization
|
||||
* or exit time.
|
||||
*/
|
||||
#define __init \
|
||||
__attribute__ ((__section__ (".init.text")))
|
||||
#define __exit \
|
||||
__attribute_used__ __attribute__ ((__section__(".text.exit")))
|
||||
#define __initdata \
|
||||
__attribute__ ((__section__ (".init.data")))
|
||||
#define __exitdata \
|
||||
__attribute_used__ __attribute__ ((__section__ (".data.exit")))
|
||||
#define __initsetup \
|
||||
__attribute_used__ __attribute__ ((__section__ (".setup.init")))
|
||||
#define __init_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".initcall.init")))
|
||||
#define __exit_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
|
||||
|
||||
/* For assembly routines
|
||||
#define __INIT .section ".text.init","ax"
|
||||
#define __FINIT .previous
|
||||
#define __INITDATA .section ".data.init","aw"
|
||||
*/
|
||||
|
||||
#endif /* _XEN_ASM_INIT_H */
|
||||
@@ -4,6 +4,25 @@
|
||||
#include <xen/config.h>
|
||||
#include <asm/init.h>
|
||||
|
||||
/*
|
||||
* Mark functions and data as being only used at initialization
|
||||
* or exit time.
|
||||
*/
|
||||
#define __init \
|
||||
__attribute__ ((__section__ (".init.text")))
|
||||
#define __exit \
|
||||
__attribute_used__ __attribute__ ((__section__(".exit.text")))
|
||||
#define __initdata \
|
||||
__attribute__ ((__section__ (".init.data")))
|
||||
#define __exitdata \
|
||||
__attribute_used__ __attribute__ ((__section__ (".exit.data")))
|
||||
#define __initsetup \
|
||||
__attribute_used__ __attribute__ ((__section__ (".init.setup")))
|
||||
#define __init_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".initcall1.init")))
|
||||
#define __exit_call \
|
||||
__attribute_used__ __attribute__ ((__section__ (".exitcall.exit")))
|
||||
|
||||
/* These macros are used to mark some functions or
|
||||
* initialized data (doesn't apply to uninitialized data)
|
||||
* as `initialization' functions. The kernel can take this
|
||||
|
||||
@@ -56,6 +56,23 @@
|
||||
1; \
|
||||
})
|
||||
|
||||
extern char _start[], _end[];
|
||||
#define is_kernel(p) ({ \
|
||||
char *__p = (char *)(unsigned long)(p); \
|
||||
(__p >= _start) && (__p <= _end); \
|
||||
})
|
||||
|
||||
extern char _stext[], _etext[];
|
||||
#define is_kernel_text(p) ({ \
|
||||
char *__p = (char *)(unsigned long)(p); \
|
||||
(__p >= _stext) && (__p <= _etext); \
|
||||
})
|
||||
|
||||
extern char _sinittext[], _einittext[];
|
||||
#define is_kernel_inittext(p) ({ \
|
||||
char *__p = (char *)(unsigned long)(p); \
|
||||
(__p >= _sinittext) && (__p <= _einittext); \
|
||||
})
|
||||
|
||||
#endif /* _LINUX_KERNEL_H */
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
#define KSYM_NAME_LEN 127
|
||||
|
||||
extern int is_kernel_text(unsigned long addr);
|
||||
extern unsigned long kernel_text_end(void);
|
||||
|
||||
/* Lookup an address. */
|
||||
const char *symbols_lookup(unsigned long addr,
|
||||
unsigned long *symbolsize,
|
||||
@@ -16,7 +13,7 @@ const char *symbols_lookup(unsigned long addr,
|
||||
char *namebuf);
|
||||
|
||||
/* Replace "%s" in format with address, if found */
|
||||
extern void __print_symbol(const char *fmt, unsigned long address);
|
||||
void __print_symbol(const char *fmt, unsigned long address);
|
||||
|
||||
/* This macro allows us to keep printk typechecking */
|
||||
static void __check_printsym_format(const char *fmt, ...)
|
||||
|
||||
+111
-330
@@ -5,7 +5,7 @@
|
||||
* This software may be used and distributed according to the terms
|
||||
* of the GNU General Public License, incorporated herein by reference.
|
||||
*
|
||||
* Usage: nm -n <object-file> | scripts/symbols [--all-symbols] > symbols.S
|
||||
* Usage: nm -n vmlinux | scripts/symbols [--all-symbols] > symbols.S
|
||||
*
|
||||
* ChangeLog:
|
||||
*
|
||||
@@ -24,75 +24,37 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* maximum token length used. It doesn't pay to increase it a lot, because
|
||||
* very long substrings probably don't repeat themselves too often. */
|
||||
#define MAX_TOK_SIZE 11
|
||||
#define KSYM_NAME_LEN 127
|
||||
|
||||
/* we use only a subset of the complete symbol table to gather the token count,
|
||||
* to speed up compression, at the expense of a little compression ratio */
|
||||
#define WORKING_SET 1024
|
||||
|
||||
/* first find the best token only on the list of tokens that would profit more
|
||||
* than GOOD_BAD_THRESHOLD. Only if this list is empty go to the "bad" list.
|
||||
* Increasing this value will put less tokens on the "good" list, so the search
|
||||
* is faster. However, if the good list runs out of tokens, we must painfully
|
||||
* search the bad list. */
|
||||
#define GOOD_BAD_THRESHOLD 10
|
||||
|
||||
/* token hash parameters */
|
||||
#define HASH_BITS 18
|
||||
#define HASH_TABLE_SIZE (1 << HASH_BITS)
|
||||
#define HASH_MASK (HASH_TABLE_SIZE - 1)
|
||||
#define HASH_BASE_OFFSET 2166136261U
|
||||
#define HASH_FOLD(a) ((a)&(HASH_MASK))
|
||||
|
||||
/* flags to mark symbols */
|
||||
#define SYM_FLAG_VALID 1
|
||||
#define SYM_FLAG_SAMPLED 2
|
||||
|
||||
struct sym_entry {
|
||||
unsigned long long addr;
|
||||
char type;
|
||||
unsigned char flags;
|
||||
unsigned char len;
|
||||
unsigned int len;
|
||||
unsigned char *sym;
|
||||
};
|
||||
|
||||
|
||||
static struct sym_entry *table;
|
||||
static int size, cnt;
|
||||
static unsigned long long _stext, _etext;
|
||||
static unsigned int table_size, table_cnt;
|
||||
static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
|
||||
static int all_symbols = 0;
|
||||
static char symbol_prefix_char = '\0';
|
||||
|
||||
struct token {
|
||||
unsigned char data[MAX_TOK_SIZE];
|
||||
unsigned char len;
|
||||
/* profit: the number of bytes that could be saved by inserting this
|
||||
* token into the table */
|
||||
int profit;
|
||||
struct token *next; /* next token on the hash list */
|
||||
struct token *right; /* next token on the good/bad list */
|
||||
struct token *left; /* previous token on the good/bad list */
|
||||
struct token *smaller; /* token that is less one letter than this one */
|
||||
};
|
||||
|
||||
struct token bad_head, good_head;
|
||||
struct token *hash_table[HASH_TABLE_SIZE];
|
||||
int token_profit[0x10000];
|
||||
|
||||
/* the table that holds the result of the compression */
|
||||
unsigned char best_table[256][MAX_TOK_SIZE+1];
|
||||
unsigned char best_table[256][2];
|
||||
unsigned char best_table_len[256];
|
||||
|
||||
|
||||
static void
|
||||
usage(void)
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: symbols [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
|
||||
exit(1);
|
||||
@@ -102,21 +64,19 @@ usage(void)
|
||||
* This ignores the intensely annoying "mapping symbols" found
|
||||
* in ARM ELF files: $a, $t and $d.
|
||||
*/
|
||||
static inline int
|
||||
is_arm_mapping_symbol(const char *str)
|
||||
static inline int is_arm_mapping_symbol(const char *str)
|
||||
{
|
||||
return str[0] == '$' && strchr("atd", str[1])
|
||||
&& (str[2] == '\0' || str[2] == '.');
|
||||
}
|
||||
|
||||
static int
|
||||
read_symbol(FILE *in, struct sym_entry *s)
|
||||
static int read_symbol(FILE *in, struct sym_entry *s)
|
||||
{
|
||||
char str[500];
|
||||
char *sym;
|
||||
char *sym, stype;
|
||||
int rc;
|
||||
|
||||
rc = fscanf(in, "%llx %c %499s\n", &s->addr, &s->type, str);
|
||||
rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str);
|
||||
if (rc != 3) {
|
||||
if (rc != EOF) {
|
||||
/* skip line */
|
||||
@@ -135,7 +95,15 @@ read_symbol(FILE *in, struct sym_entry *s)
|
||||
_stext = s->addr;
|
||||
else if (strcmp(sym, "_etext") == 0)
|
||||
_etext = s->addr;
|
||||
else if (toupper(s->type) == 'A')
|
||||
else if (strcmp(sym, "_sinittext") == 0)
|
||||
_sinittext = s->addr;
|
||||
else if (strcmp(sym, "_einittext") == 0)
|
||||
_einittext = s->addr;
|
||||
else if (strcmp(sym, "_sextratext") == 0)
|
||||
_sextratext = s->addr;
|
||||
else if (strcmp(sym, "_eextratext") == 0)
|
||||
_eextratext = s->addr;
|
||||
else if (toupper(stype) == 'A')
|
||||
{
|
||||
/* Keep these useful absolute symbols */
|
||||
if (strcmp(sym, "__kernel_syscall_via_break") &&
|
||||
@@ -145,22 +113,24 @@ read_symbol(FILE *in, struct sym_entry *s)
|
||||
return -1;
|
||||
|
||||
}
|
||||
else if (toupper(s->type) == 'U' ||
|
||||
else if (toupper(stype) == 'U' ||
|
||||
is_arm_mapping_symbol(sym))
|
||||
return -1;
|
||||
/* exclude also MIPS ELF local symbols ($L123 instead of .L123) */
|
||||
else if (str[0] == '$')
|
||||
return -1;
|
||||
|
||||
/* include the type field in the symbol name, so that it gets
|
||||
* compressed together */
|
||||
s->len = strlen(str) + 1;
|
||||
s->sym = (unsigned char *) malloc(s->len + 1);
|
||||
s->sym = malloc(s->len + 1);
|
||||
strcpy((char *)s->sym + 1, str);
|
||||
s->sym[0] = s->type;
|
||||
s->sym[0] = stype;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
symbol_valid(struct sym_entry *s)
|
||||
static int symbol_valid(struct sym_entry *s)
|
||||
{
|
||||
/* Symbols which vary between passes. Passes 1 and 2 must have
|
||||
* identical symbol lists. The symbols_* symbols below are only added
|
||||
@@ -189,7 +159,9 @@ symbol_valid(struct sym_entry *s)
|
||||
/* if --all-symbols is not specified, then symbols outside the text
|
||||
* and inittext sections are discarded */
|
||||
if (!all_symbols) {
|
||||
if (s->addr < _stext || s->addr > _etext)
|
||||
if ((s->addr < _stext || s->addr > _etext)
|
||||
&& (s->addr < _sinittext || s->addr > _einittext)
|
||||
&& (s->addr < _sextratext || s->addr > _eextratext))
|
||||
return 0;
|
||||
/* Corner case. Discard any symbols with the same value as
|
||||
* _etext _einittext or _eextratext; they can move between pass
|
||||
@@ -197,7 +169,9 @@ symbol_valid(struct sym_entry *s)
|
||||
* move then they may get dropped in pass 2, which breaks the
|
||||
* symbols rules.
|
||||
*/
|
||||
if (s->addr == _etext && strcmp((char *)s->sym + offset, "_etext"))
|
||||
if ((s->addr == _etext && strcmp((char*)s->sym + offset, "_etext")) ||
|
||||
(s->addr == _einittext && strcmp((char*)s->sym + offset, "_einittext")) ||
|
||||
(s->addr == _eextratext && strcmp((char*)s->sym + offset, "_eextratext")))
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -212,20 +186,19 @@ symbol_valid(struct sym_entry *s)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
read_map(FILE *in)
|
||||
static void read_map(FILE *in)
|
||||
{
|
||||
while (!feof(in)) {
|
||||
if (cnt >= size) {
|
||||
size += 10000;
|
||||
table = realloc(table, sizeof(*table) * size);
|
||||
if (table_cnt >= table_size) {
|
||||
table_size += 10000;
|
||||
table = realloc(table, sizeof(*table) * table_size);
|
||||
if (!table) {
|
||||
fprintf(stderr, "out of memory\n");
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
if (read_symbol(in, &table[cnt]) == 0)
|
||||
cnt++;
|
||||
if (read_symbol(in, &table[table_cnt]) == 0)
|
||||
table_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,10 +242,9 @@ static int expand_symbol(unsigned char *data, int len, char *result)
|
||||
return total;
|
||||
}
|
||||
|
||||
static void
|
||||
write_src(void)
|
||||
static void write_src(void)
|
||||
{
|
||||
int i, k, off, valid;
|
||||
unsigned int i, k, off;
|
||||
unsigned int best_idx[256];
|
||||
unsigned int *markers;
|
||||
char buf[KSYM_NAME_LEN+1];
|
||||
@@ -289,33 +261,24 @@ write_src(void)
|
||||
printf(".data\n");
|
||||
|
||||
output_label("symbols_addresses");
|
||||
valid = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (table[i].flags & SYM_FLAG_VALID) {
|
||||
printf("\tPTR\t%#llx\n", table[i].addr);
|
||||
valid++;
|
||||
}
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
printf("\tPTR\t%#llx\n", table[i].addr);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
output_label("symbols_num_syms");
|
||||
printf("\tPTR\t%d\n", valid);
|
||||
printf("\tPTR\t%d\n", table_cnt);
|
||||
printf("\n");
|
||||
|
||||
/* table of offset markers, that give the offset in the compressed stream
|
||||
* every 256 symbols */
|
||||
markers = (unsigned int *) malloc(sizeof(unsigned int)*((valid + 255) / 256));
|
||||
markers = (unsigned int *) malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256));
|
||||
|
||||
output_label("symbols_names");
|
||||
valid = 0;
|
||||
off = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
|
||||
if (!(table[i].flags & SYM_FLAG_VALID))
|
||||
continue;
|
||||
|
||||
if ((valid & 0xFF) == 0)
|
||||
markers[valid >> 8] = off;
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
if ((i & 0xFF) == 0)
|
||||
markers[i >> 8] = off;
|
||||
|
||||
printf("\t.byte 0x%02x", table[i].len);
|
||||
for (k = 0; k < table[i].len; k++)
|
||||
@@ -323,12 +286,11 @@ write_src(void)
|
||||
printf("\n");
|
||||
|
||||
off += table[i].len + 1;
|
||||
valid++;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
output_label("symbols_markers");
|
||||
for (i = 0; i < ((valid + 255) >> 8); i++)
|
||||
for (i = 0; i < ((table_cnt + 255) >> 8); i++)
|
||||
printf("\tPTR\t%d\n", markers[i]);
|
||||
printf("\n");
|
||||
|
||||
@@ -338,7 +300,7 @@ write_src(void)
|
||||
off = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
best_idx[i] = off;
|
||||
expand_symbol(best_table[i],best_table_len[i],buf);
|
||||
expand_symbol(best_table[i], best_table_len[i], buf);
|
||||
printf("\t.asciz\t\"%s\"\n", buf);
|
||||
off += strlen(buf) + 1;
|
||||
}
|
||||
@@ -353,153 +315,13 @@ write_src(void)
|
||||
|
||||
/* table lookup compression functions */
|
||||
|
||||
static inline unsigned int rehash_token(unsigned int hash, unsigned char data)
|
||||
{
|
||||
return ((hash * 16777619) ^ data);
|
||||
}
|
||||
|
||||
static unsigned int hash_token(unsigned char *data, int len)
|
||||
{
|
||||
unsigned int hash=HASH_BASE_OFFSET;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
hash = rehash_token(hash, data[i]);
|
||||
|
||||
return HASH_FOLD(hash);
|
||||
}
|
||||
|
||||
/* find a token given its data and hash value */
|
||||
static struct token *find_token_hash(unsigned char *data, int len, unsigned int hash)
|
||||
{
|
||||
struct token *ptr;
|
||||
|
||||
ptr = hash_table[hash];
|
||||
|
||||
while (ptr) {
|
||||
if ((ptr->len == len) && (memcmp(ptr->data, data, len) == 0))
|
||||
return ptr;
|
||||
ptr=ptr->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void insert_token_in_group(struct token *head, struct token *ptr)
|
||||
{
|
||||
ptr->right = head->right;
|
||||
ptr->right->left = ptr;
|
||||
head->right = ptr;
|
||||
ptr->left = head;
|
||||
}
|
||||
|
||||
static inline void remove_token_from_group(struct token *ptr)
|
||||
{
|
||||
ptr->left->right = ptr->right;
|
||||
ptr->right->left = ptr->left;
|
||||
}
|
||||
|
||||
|
||||
/* build the counts for all the tokens that start with "data", and have lenghts
|
||||
* from 2 to "len" */
|
||||
static void learn_token(unsigned char *data, int len)
|
||||
{
|
||||
struct token *ptr,*last_ptr;
|
||||
int i, newprofit;
|
||||
unsigned int hash = HASH_BASE_OFFSET;
|
||||
unsigned int hashes[MAX_TOK_SIZE + 1];
|
||||
|
||||
if (len > MAX_TOK_SIZE)
|
||||
len = MAX_TOK_SIZE;
|
||||
|
||||
/* calculate and store the hash values for all the sub-tokens */
|
||||
hash = rehash_token(hash, data[0]);
|
||||
for (i = 2; i <= len; i++) {
|
||||
hash = rehash_token(hash, data[i-1]);
|
||||
hashes[i] = HASH_FOLD(hash);
|
||||
}
|
||||
|
||||
last_ptr = NULL;
|
||||
ptr = NULL;
|
||||
|
||||
for (i = len; i >= 2; i--) {
|
||||
hash = hashes[i];
|
||||
|
||||
if (!ptr) ptr = find_token_hash(data, i, hash);
|
||||
|
||||
if (!ptr) {
|
||||
/* create a new token entry */
|
||||
ptr = (struct token *) malloc(sizeof(*ptr));
|
||||
|
||||
memcpy(ptr->data, data, i);
|
||||
ptr->len = i;
|
||||
|
||||
/* when we create an entry, it's profit is 0 because
|
||||
* we also take into account the size of the token on
|
||||
* the compressed table. We then subtract GOOD_BAD_THRESHOLD
|
||||
* so that the test to see if this token belongs to
|
||||
* the good or bad list, is a comparison to zero */
|
||||
ptr->profit = -GOOD_BAD_THRESHOLD;
|
||||
|
||||
ptr->next = hash_table[hash];
|
||||
hash_table[hash] = ptr;
|
||||
|
||||
insert_token_in_group(&bad_head, ptr);
|
||||
|
||||
ptr->smaller = NULL;
|
||||
} else {
|
||||
newprofit = ptr->profit + (ptr->len - 1);
|
||||
/* check to see if this token needs to be moved to a
|
||||
* different list */
|
||||
if((ptr->profit < 0) && (newprofit >= 0)) {
|
||||
remove_token_from_group(ptr);
|
||||
insert_token_in_group(&good_head,ptr);
|
||||
}
|
||||
ptr->profit = newprofit;
|
||||
}
|
||||
|
||||
if (last_ptr) last_ptr->smaller = ptr;
|
||||
last_ptr = ptr;
|
||||
|
||||
ptr = ptr->smaller;
|
||||
}
|
||||
}
|
||||
|
||||
/* decrease the counts for all the tokens that start with "data", and have lenghts
|
||||
* from 2 to "len". This function is much simpler than learn_token because we have
|
||||
* more guarantees (tho tokens exist, the ->smaller pointer is set, etc.)
|
||||
* The two separate functions exist only because of compression performance */
|
||||
static void forget_token(unsigned char *data, int len)
|
||||
{
|
||||
struct token *ptr;
|
||||
int i, newprofit;
|
||||
unsigned int hash=0;
|
||||
|
||||
if (len > MAX_TOK_SIZE) len = MAX_TOK_SIZE;
|
||||
|
||||
hash = hash_token(data, len);
|
||||
ptr = find_token_hash(data, len, hash);
|
||||
|
||||
for (i = len; i >= 2; i--) {
|
||||
|
||||
newprofit = ptr->profit - (ptr->len - 1);
|
||||
if ((ptr->profit >= 0) && (newprofit < 0)) {
|
||||
remove_token_from_group(ptr);
|
||||
insert_token_in_group(&bad_head, ptr);
|
||||
}
|
||||
ptr->profit=newprofit;
|
||||
|
||||
ptr=ptr->smaller;
|
||||
}
|
||||
}
|
||||
|
||||
/* count all the possible tokens in a symbol */
|
||||
static void learn_symbol(unsigned char *symbol, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len - 1; i++)
|
||||
learn_token(symbol + i, len - i);
|
||||
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++;
|
||||
}
|
||||
|
||||
/* decrease the count for all the possible tokens in a symbol */
|
||||
@@ -508,117 +330,90 @@ static void forget_symbol(unsigned char *symbol, int len)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len - 1; i++)
|
||||
forget_token(symbol + i, len - i);
|
||||
token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--;
|
||||
}
|
||||
|
||||
/* set all the symbol flags and do the initial token count */
|
||||
/* remove all the invalid symbols from the table and do the initial token count */
|
||||
static void build_initial_tok_table(void)
|
||||
{
|
||||
int i, use_it, valid;
|
||||
unsigned int i, pos;
|
||||
|
||||
valid = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
table[i].flags = 0;
|
||||
pos = 0;
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
if ( symbol_valid(&table[i]) ) {
|
||||
table[i].flags |= SYM_FLAG_VALID;
|
||||
valid++;
|
||||
if (pos != i)
|
||||
table[pos] = table[i];
|
||||
learn_symbol(table[pos].sym, table[pos].len);
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
|
||||
use_it = 0;
|
||||
for (i = 0; i < cnt; i++) {
|
||||
|
||||
/* subsample the available symbols. This method is almost like
|
||||
* a Bresenham's algorithm to get uniformly distributed samples
|
||||
* across the symbol table */
|
||||
if (table[i].flags & SYM_FLAG_VALID) {
|
||||
|
||||
use_it += WORKING_SET;
|
||||
|
||||
if (use_it >= valid) {
|
||||
table[i].flags |= SYM_FLAG_SAMPLED;
|
||||
use_it -= valid;
|
||||
}
|
||||
}
|
||||
if (table[i].flags & SYM_FLAG_SAMPLED)
|
||||
learn_symbol(table[i].sym, table[i].len);
|
||||
}
|
||||
table_cnt = pos;
|
||||
}
|
||||
|
||||
/* replace a given token in all the valid symbols. Use the sampled symbols
|
||||
* to update the counts */
|
||||
static void compress_symbols(unsigned char *str, int tlen, int idx)
|
||||
static void compress_symbols(unsigned char *str, int idx)
|
||||
{
|
||||
int i, len, learn, size;
|
||||
unsigned char *p;
|
||||
unsigned int i, len, size;
|
||||
unsigned char *p1, *p2;
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
|
||||
if (!(table[i].flags & SYM_FLAG_VALID)) continue;
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
|
||||
len = table[i].len;
|
||||
learn = 0;
|
||||
p = table[i].sym;
|
||||
p1 = table[i].sym;
|
||||
|
||||
/* find the token on the symbol */
|
||||
p2 = memmem(p1, len, str, 2);
|
||||
if (!p2) continue;
|
||||
|
||||
/* decrease the counts for this symbol's tokens */
|
||||
forget_symbol(table[i].sym, len);
|
||||
|
||||
size = len;
|
||||
|
||||
do {
|
||||
*p2 = idx;
|
||||
p2++;
|
||||
size -= (p2 - p1);
|
||||
memmove(p2, p2 + 1, size);
|
||||
p1 = p2;
|
||||
len--;
|
||||
|
||||
if (size < 2) break;
|
||||
|
||||
/* find the token on the symbol */
|
||||
p = (unsigned char *) strstr((char *) p, (char *) str);
|
||||
if (!p) break;
|
||||
p2 = memmem(p1, size, str, 2);
|
||||
|
||||
if (!learn) {
|
||||
/* if this symbol was used to count, decrease it */
|
||||
if (table[i].flags & SYM_FLAG_SAMPLED)
|
||||
forget_symbol(table[i].sym, len);
|
||||
learn = 1;
|
||||
}
|
||||
} while (p2);
|
||||
|
||||
*p = idx;
|
||||
size = (len - (p - table[i].sym)) - tlen + 1;
|
||||
memmove(p + 1, p + tlen, size);
|
||||
p++;
|
||||
len -= tlen - 1;
|
||||
table[i].len = len;
|
||||
|
||||
} while (size >= tlen);
|
||||
|
||||
if(learn) {
|
||||
table[i].len = len;
|
||||
/* if this symbol was used to count, learn it again */
|
||||
if(table[i].flags & SYM_FLAG_SAMPLED)
|
||||
learn_symbol(table[i].sym, len);
|
||||
}
|
||||
/* increase the counts for this symbol's new tokens */
|
||||
learn_symbol(table[i].sym, len);
|
||||
}
|
||||
}
|
||||
|
||||
/* search the token with the maximum profit */
|
||||
static struct token *find_best_token(void)
|
||||
static int find_best_token(void)
|
||||
{
|
||||
struct token *ptr,*best,*head;
|
||||
int bestprofit;
|
||||
int i, best, bestprofit;
|
||||
|
||||
bestprofit=-10000;
|
||||
best = 0;
|
||||
|
||||
/* failsafe: if the "good" list is empty search from the "bad" list */
|
||||
if(good_head.right == &good_head) head = &bad_head;
|
||||
else head = &good_head;
|
||||
|
||||
ptr = head->right;
|
||||
best = NULL;
|
||||
while (ptr != head) {
|
||||
if (ptr->profit > bestprofit) {
|
||||
bestprofit = ptr->profit;
|
||||
best = ptr;
|
||||
for (i = 0; i < 0x10000; i++) {
|
||||
if (token_profit[i] > bestprofit) {
|
||||
best = i;
|
||||
bestprofit = token_profit[i];
|
||||
}
|
||||
ptr = ptr->right;
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
/* this is the core of the algorithm: calculate the "best" table */
|
||||
static void optimize_result(void)
|
||||
{
|
||||
struct token *best;
|
||||
int i;
|
||||
int i, best;
|
||||
|
||||
/* using the '\0' symbol last allows compress_symbols to use standard
|
||||
* fast string functions */
|
||||
@@ -632,14 +427,12 @@ static void optimize_result(void)
|
||||
best = find_best_token();
|
||||
|
||||
/* place it in the "best" table */
|
||||
best_table_len[i] = best->len;
|
||||
memcpy(best_table[i], best->data, best_table_len[i]);
|
||||
/* zero terminate the token so that we can use strstr
|
||||
in compress_symbols */
|
||||
best_table[i][best_table_len[i]]='\0';
|
||||
best_table_len[i] = 2;
|
||||
best_table[i][0] = best & 0xFF;
|
||||
best_table[i][1] = (best >> 8) & 0xFF;
|
||||
|
||||
/* replace this token in all the valid symbols */
|
||||
compress_symbols(best_table[i], best_table_len[i], i);
|
||||
compress_symbols(best_table[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -647,39 +440,28 @@ static void optimize_result(void)
|
||||
/* start by placing the symbols that are actually used on the table */
|
||||
static void insert_real_symbols_in_table(void)
|
||||
{
|
||||
int i, j, c;
|
||||
unsigned int i, j, c;
|
||||
|
||||
memset(best_table, 0, sizeof(best_table));
|
||||
memset(best_table_len, 0, sizeof(best_table_len));
|
||||
|
||||
for (i = 0; i < cnt; i++) {
|
||||
if (table[i].flags & SYM_FLAG_VALID) {
|
||||
for (j = 0; j < table[i].len; j++) {
|
||||
c = table[i].sym[j];
|
||||
best_table[c][0]=c;
|
||||
best_table_len[c]=1;
|
||||
}
|
||||
for (i = 0; i < table_cnt; i++) {
|
||||
for (j = 0; j < table[i].len; j++) {
|
||||
c = table[i].sym[j];
|
||||
best_table[c][0]=c;
|
||||
best_table_len[c]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void optimize_token_table(void)
|
||||
{
|
||||
memset(hash_table, 0, sizeof(hash_table));
|
||||
|
||||
good_head.left = &good_head;
|
||||
good_head.right = &good_head;
|
||||
|
||||
bad_head.left = &bad_head;
|
||||
bad_head.right = &bad_head;
|
||||
|
||||
build_initial_tok_table();
|
||||
|
||||
insert_real_symbols_in_table();
|
||||
|
||||
/* When valid symbol is not registered, exit to error */
|
||||
if (good_head.left == good_head.right &&
|
||||
bad_head.left == bad_head.right) {
|
||||
if (!table_cnt) {
|
||||
fprintf(stderr, "No valid symbol.\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -688,8 +470,7 @@ static void optimize_token_table(void)
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc >= 2) {
|
||||
int i;
|
||||
|
||||