public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] new kallsyms approach
@ 2005-09-08 14:58 Jan Beulich
  2005-09-09  3:47 ` Andi Kleen
  0 siblings, 1 reply; 3+ messages in thread
From: Jan Beulich @ 2005-09-08 14:58 UTC (permalink / raw)
  To: linux-kernel

[-- Attachment #1: Type: text/plain, Size: 959 bytes --]

(Note: Patch only attached due to size restrictions.)

This patch provides al alternative to the pre-exisiting kallsyms code.
That code, from a kernel debugger perspective at least, suffers from
incomplete information, making it impossible to
(a) disambiguate multiple static functions of the same name (in
different
source files),
(b) determine a complete set of attributes for a symbol (namely, the
symbol's size, but also its type, which gets converted to an nm-like
one-
character representation), and
(c) retain full section information

This new approach basically makes handling core kernel and module
symbols
the same, by retrieving the kernel's section, symbol, and string
tables
rather than parsing the system map.

At once it adds the functionality to strip unneeded symbols from
modules,
which results in non-neglectable space savings for typical
distributions
(which large amounts of modules).

Signed-off-by: Jan Beulich <jbeulich@novell.com>



[-- Attachment #2: linux-2.6.13-kallsyms.patch --]
[-- Type: application/octet-stream, Size: 70744 bytes --]

(Note: Patch only attached due to size restrictions.)

This patch provides al alternative to the pre-exisiting kallsyms code.
That code, from a kernel debugger perspective at least, suffers from
incomplete information, making it impossible to
(a) disambiguate multiple static functions of the same name (in different
source files),
(b) determine a complete set of attributes for a symbol (namely, the
symbol's size, but also its type, which gets converted to an nm-like one-
character representation), and
(c) retain full section information

This new approach basically makes handling core kernel and module symbols
the same, by retrieving the kernel's section, symbol, and string tables
rather than parsing the system map.

At once it adds the functionality to strip unneeded symbols from modules,
which results in non-neglectable space savings for typical distributions
(which large amounts of modules).

Signed-off-by: Jan Beulich <jbeulich@novell.com>

diff -Npru 2.6.13/arch/alpha/defconfig 2.6.13-kallsyms/arch/alpha/defconfig
--- 2.6.13/arch/alpha/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/alpha/defconfig	2005-09-07 12:36:02.000000000 +0200
@@ -32,6 +32,7 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
diff -Npru 2.6.13/arch/frv/defconfig 2.6.13-kallsyms/arch/frv/defconfig
--- 2.6.13/arch/frv/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/frv/defconfig	2005-09-07 12:34:09.000000000 +0200
@@ -33,6 +33,7 @@ CONFIG_SYSCTL=y
 # CONFIG_IKCONFIG is not set
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_PRINTK=y
diff -Npru 2.6.13/arch/i386/defconfig 2.6.13-kallsyms/arch/i386/defconfig
--- 2.6.13/arch/i386/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/i386/defconfig	2005-09-07 12:32:14.000000000 +0200
@@ -28,6 +28,8 @@ CONFIG_HOTPLUG=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_IOSCHED_NOOP=y
diff -Npru 2.6.13/arch/i386/kernel/entry.S 2.6.13-kallsyms/arch/i386/kernel/entry.S
--- 2.6.13/arch/i386/kernel/entry.S	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/i386/kernel/entry.S	2005-09-07 16:22:19.000000000 +0200
@@ -129,6 +129,7 @@ ENTRY(ret_from_fork)
 	GET_THREAD_INFO(%ebp)
 	popl %eax
 	jmp syscall_exit
+END(ret_from_fork)
 
 /*
  * Return to user mode is not as complex as all this looks,
@@ -156,6 +157,7 @@ ENTRY(resume_userspace)
 					# int/exception return?
 	jne work_pending
 	jmp restore_all
+END(ret_from_exception)
 
 #ifdef CONFIG_PREEMPT
 ENTRY(resume_kernel)
@@ -170,6 +172,7 @@ need_resched:
 	jz restore_all
 	call preempt_schedule_irq
 	jmp need_resched
+END(resume_kernel)
 #endif
 
 /* SYSENTER_RETURN points to after the "sysenter" instruction in
@@ -219,6 +222,7 @@ sysenter_past_esp:
 	xorl %ebp,%ebp
 	sti
 	sysexit
+ENDPROC(sysenter_entry)
 
 
 	# system call handler stub
@@ -293,6 +297,7 @@ ldt_ss:
 	.align 4
 	.long 1b,iret_exc
 .previous
+ENDPROC(system_call)
 
 	# perform work that needs to be done immediately before resumption
 	ALIGN
@@ -330,6 +335,7 @@ work_notifysig_v86:
 	xorl %edx, %edx
 	call do_notify_resume
 	jmp restore_all
+END(work_pending)
 
 	# perform syscall exit tracing
 	ALIGN
@@ -342,6 +348,7 @@ syscall_trace_entry:
 	cmpl $(nr_syscalls), %eax
 	jnae syscall_call
 	jmp syscall_exit
+END(syscall_trace_entry)
 
 	# perform syscall exit tracing
 	ALIGN
@@ -354,6 +361,7 @@ syscall_exit_work:
 	movl $1, %edx
 	call do_syscall_trace
 	jmp resume_userspace
+END(syscall_exit_work)
 
 	ALIGN
 syscall_fault:
@@ -362,11 +370,13 @@ syscall_fault:
 	GET_THREAD_INFO(%ebp)
 	movl $-EFAULT,EAX(%esp)
 	jmp resume_userspace
+END(syscall_fault)
 
 	ALIGN
 syscall_badsys:
 	movl $-ENOSYS,EAX(%esp)
 	jmp resume_userspace
+END(syscall_badsys)
 
 #define FIXUP_ESPFIX_STACK \
 	movl %esp, %eax; \
@@ -395,19 +405,24 @@ syscall_badsys:
  */
 .data
 ENTRY(interrupt)
-.text
+.previous
 
-vector=0
 ENTRY(irq_entries_start)
+vector=0
 .rept NR_IRQS
 	ALIGN
 1:	pushl $vector-256
 	jmp common_interrupt
-.data
+ .data
 	.long 1b
-.text
-vector=vector+1
+ .previous
+ vector=vector+1
 .endr
+END(irq_entries_start)
+
+.data
+END(interrupt)
+.previous
 
 	ALIGN
 common_interrupt:
@@ -415,6 +430,7 @@ common_interrupt:
 	movl %esp,%eax
 	call do_IRQ
 	jmp ret_from_intr
+ENDPROC(common_interrupt)
 
 #define BUILD_INTERRUPT(name, nr)	\
 ENTRY(name)				\
@@ -422,7 +438,8 @@ ENTRY(name)				\
 	SAVE_ALL			\
 	movl %esp,%eax;			\
 	call smp_/**/name;		\
-	jmp ret_from_intr;
+	jmp ret_from_intr;	\
+ENDPROC(name)
 
 /* The include is where all of the SMP etc. interrupts come from */
 #include "entry_arch.h"
@@ -430,6 +447,7 @@ ENTRY(name)				\
 ENTRY(divide_error)
 	pushl $0			# no error code
 	pushl $do_divide_error
+END(divide_error)
 	ALIGN
 error_code:
 	pushl %ds
@@ -456,16 +474,19 @@ error_code:
 	movl %esp,%eax			# pt_regs pointer
 	call *%edi
 	jmp ret_from_exception
+ENDPROC(error_code)
 
 ENTRY(coprocessor_error)
 	pushl $0
 	pushl $do_coprocessor_error
 	jmp error_code
+END(coprocessor_error)
 
 ENTRY(simd_coprocessor_error)
 	pushl $0
 	pushl $do_simd_coprocessor_error
 	jmp error_code
+END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
 	pushl $-1			# mark this as an int
@@ -481,6 +502,7 @@ device_not_available_emulate:
 	call math_emulate
 	addl $4, %esp
 	jmp ret_from_exception
+END(device_not_available)
 
 /*
  * Debug traps and NMI can happen at the one SYSENTER instruction
@@ -515,6 +537,7 @@ debug_stack_correct:
 	movl %esp,%eax			# pt_regs pointer
 	call do_debug
 	jmp ret_from_exception
+END(debug)
 
 /*
  * NMI is doubly nasty. It can happen _while_ we're handling
@@ -587,6 +610,7 @@ nmi_16bit_stack:
 	.align 4
 	.long 1b,iret_exc
 .previous
+ENDPROC(nmi)
 
 ENTRY(int3)
 	pushl $-1			# mark this as an int
@@ -595,62 +619,75 @@ ENTRY(int3)
 	movl %esp,%eax		# pt_regs pointer
 	call do_int3
 	jmp ret_from_exception
+END(int3)
 
 ENTRY(overflow)
 	pushl $0
 	pushl $do_overflow
 	jmp error_code
+END(overflow)
 
 ENTRY(bounds)
 	pushl $0
 	pushl $do_bounds
 	jmp error_code
+END(bounds)
 
 ENTRY(invalid_op)
 	pushl $0
 	pushl $do_invalid_op
 	jmp error_code
+END(invalid_op)
 
 ENTRY(coprocessor_segment_overrun)
 	pushl $0
 	pushl $do_coprocessor_segment_overrun
 	jmp error_code
+END(coprocessor_segment_overrun)
 
 ENTRY(invalid_TSS)
 	pushl $do_invalid_TSS
 	jmp error_code
+END(invalid_TSS)
 
 ENTRY(segment_not_present)
 	pushl $do_segment_not_present
 	jmp error_code
+END(segment_not_present)
 
 ENTRY(stack_segment)
 	pushl $do_stack_segment
 	jmp error_code
+END(stack_segment)
 
 ENTRY(general_protection)
 	pushl $do_general_protection
 	jmp error_code
+END(general_protection)
 
 ENTRY(alignment_check)
 	pushl $do_alignment_check
 	jmp error_code
+END(alignment_check)
 
 ENTRY(page_fault)
 	pushl $do_page_fault
 	jmp error_code
+END(page_fault)
 
 #ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
 	pushl $0
 	pushl machine_check_vector
 	jmp error_code
+END(machine_check)
 #endif
 
 ENTRY(spurious_interrupt_bug)
 	pushl $0
 	pushl $do_spurious_interrupt_bug
 	jmp error_code
+END(spurious_interrupt_bug)
 
 #include "syscall_table.S"
 
diff -Npru 2.6.13/arch/ia64/defconfig 2.6.13-kallsyms/arch/ia64/defconfig
--- 2.6.13/arch/ia64/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/ia64/defconfig	2005-09-07 12:34:27.000000000 +0200
@@ -29,6 +29,7 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_PRINTK=y
diff -Npru 2.6.13/arch/ia64/Makefile 2.6.13-kallsyms/arch/ia64/Makefile
--- 2.6.13/arch/ia64/Makefile	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/ia64/Makefile	2005-09-07 11:52:28.000000000 +0200
@@ -9,7 +9,6 @@
 #
 
 NM := $(CROSS_COMPILE)nm -B
-READELF := $(CROSS_COMPILE)readelf
 
 export AWK
 
diff -Npru 2.6.13/arch/m68k/defconfig 2.6.13-kallsyms/arch/m68k/defconfig
--- 2.6.13/arch/m68k/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/m68k/defconfig	2005-09-07 12:34:56.000000000 +0200
@@ -32,6 +32,7 @@ CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_PRINTK=y
 CONFIG_BUG=y
diff -Npru 2.6.13/arch/mips/defconfig 2.6.13-kallsyms/arch/mips/defconfig
--- 2.6.13/arch/mips/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/mips/defconfig	2005-09-07 12:35:22.000000000 +0200
@@ -32,6 +32,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 CONFIG_EMBEDDED=y
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
diff -Npru 2.6.13/arch/ppc64/defconfig 2.6.13-kallsyms/arch/ppc64/defconfig
--- 2.6.13/arch/ppc64/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/ppc64/defconfig	2005-09-07 12:36:57.000000000 +0200
@@ -39,6 +39,7 @@ CONFIG_IKCONFIG_PROC=y
 CONFIG_CPUSETS=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_PRINTK=y
diff -Npru 2.6.13/arch/s390/defconfig 2.6.13-kallsyms/arch/s390/defconfig
--- 2.6.13/arch/s390/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/s390/defconfig	2005-09-07 12:35:46.000000000 +0200
@@ -35,6 +35,7 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_PRINTK=y
diff -Npru 2.6.13/arch/sparc/defconfig 2.6.13-kallsyms/arch/sparc/defconfig
--- 2.6.13/arch/sparc/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/sparc/defconfig	2005-09-07 12:37:27.000000000 +0200
@@ -28,7 +28,9 @@ CONFIG_LOG_BUF_SHIFT=14
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
 CONFIG_EPOLL=y
 CONFIG_IOSCHED_NOOP=y
diff -Npru 2.6.13/arch/sparc64/defconfig 2.6.13-kallsyms/arch/sparc64/defconfig
--- 2.6.13/arch/sparc64/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/sparc64/defconfig	2005-09-07 12:37:48.000000000 +0200
@@ -30,6 +30,7 @@ CONFIG_KOBJECT_UEVENT=y
 # CONFIG_IKCONFIG is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_ALL is not set
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_FUTEX=y
diff -Npru 2.6.13/arch/um/defconfig 2.6.13-kallsyms/arch/um/defconfig
--- 2.6.13/arch/um/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/um/defconfig	2005-09-07 12:33:51.000000000 +0200
@@ -70,6 +70,7 @@ CONFIG_IKCONFIG=y
 CONFIG_IKCONFIG_PROC=y
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 # CONFIG_KALLSYMS_ALL is not set
 CONFIG_KALLSYMS_EXTRA_PASS=y
 CONFIG_PRINTK=y
diff -Npru 2.6.13/arch/x86_64/defconfig 2.6.13-kallsyms/arch/x86_64/defconfig
--- 2.6.13/arch/x86_64/defconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/x86_64/defconfig	2005-09-07 12:38:00.000000000 +0200
@@ -39,6 +39,7 @@ CONFIG_IKCONFIG_PROC=y
 # CONFIG_CPUSETS is not set
 # CONFIG_EMBEDDED is not set
 CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_TRADITIONAL=y
 CONFIG_KALLSYMS_ALL=y
 # CONFIG_KALLSYMS_EXTRA_PASS is not set
 CONFIG_PRINTK=y
diff -Npru 2.6.13/arch/x86_64/kernel/entry.S 2.6.13-kallsyms/arch/x86_64/kernel/entry.S
--- 2.6.13/arch/x86_64/kernel/entry.S	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/arch/x86_64/kernel/entry.S	2005-09-05 14:56:11.000000000 +0200
@@ -143,6 +143,7 @@ rff_trace:
 	GET_THREAD_INFO(%rcx)	
 	jmp rff_action
 	CFI_ENDPROC
+END(ret_from_fork)
 
 /*
  * System call entry. Upto 6 arguments in registers are supported.
@@ -254,6 +255,7 @@ tracesys:			 
 	RESTORE_TOP_OF_STACK %rbx
 	RESTORE_REST
 	jmp ret_from_sys_call
+END(system_call)
 		
 badsys:
 	movq $-ENOSYS,RAX-ARGOFFSET(%rsp)	
@@ -316,6 +318,7 @@ int_restore_rest:
 	cli
 	jmp int_with_check
 	CFI_ENDPROC
+END(int_ret_from_sys_call)
 		
 /* 
  * Certain special system calls that need to save a complete full stack frame.
@@ -327,6 +330,7 @@ int_restore_rest:
 	leaq	\func(%rip),%rax
 	leaq    -ARGOFFSET+8(%rsp),\arg /* 8 for return address */
 	jmp	ptregscall_common
+END(\label)
 	.endm
 
 	PTREGSCALL stub_clone, sys_clone, %r8
@@ -351,6 +355,7 @@ ENTRY(ptregscall_common)
 	CFI_ADJUST_CFA_OFFSET	8
 	ret
 	CFI_ENDPROC
+END(ptregscall_common)
 	
 ENTRY(stub_execve)
 	CFI_STARTPROC
@@ -375,6 +380,7 @@ exec_32bit:
 	RESTORE_REST
 	jmp int_ret_from_sys_call
 	CFI_ENDPROC
+END(stub_execve)
 	
 /*
  * sigreturn is special because it needs to restore all registers on return.
@@ -391,6 +397,7 @@ ENTRY(stub_rt_sigreturn)
 	RESTORE_REST
 	jmp int_ret_from_sys_call
 	CFI_ENDPROC
+END(stub_rt_sigreturn)
 
 /* 
  * Interrupt entry/exit.
@@ -516,8 +523,10 @@ retint_kernel:	
 	jnc  retint_restore_args
 	call preempt_schedule_irq
 	jmp exit_intr
-#endif	
+#endif
+
 	CFI_ENDPROC
+END(common_interrupt)
 	
 /*
  * APIC interrupts.
@@ -531,6 +540,7 @@ retint_kernel:	
 
 ENTRY(thermal_interrupt)
 	apicinterrupt THERMAL_APIC_VECTOR,smp_thermal_interrupt
+END(thermal_interrupt)
 
 #ifdef CONFIG_SMP	
 ENTRY(reschedule_interrupt)
@@ -538,20 +548,25 @@ ENTRY(reschedule_interrupt)
 
 ENTRY(invalidate_interrupt)
 	apicinterrupt INVALIDATE_TLB_VECTOR,smp_invalidate_interrupt
+END(invalidate_interrupt)
 
 ENTRY(call_function_interrupt)
 	apicinterrupt CALL_FUNCTION_VECTOR,smp_call_function_interrupt
+END(call_function_interrupt)
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC	
 ENTRY(apic_timer_interrupt)
 	apicinterrupt LOCAL_TIMER_VECTOR,smp_apic_timer_interrupt
+END(apic_timer_interrupt)
 
 ENTRY(error_interrupt)
 	apicinterrupt ERROR_APIC_VECTOR,smp_error_interrupt
+END(error_interrupt)
 
 ENTRY(spurious_interrupt)
 	apicinterrupt SPURIOUS_APIC_VECTOR,smp_spurious_interrupt
+END(spurious_interrupt)
 #endif
 				
 /*
@@ -675,6 +690,7 @@ error_kernelspace:
 	cmpq $gs_change,RIP(%rsp)
         je   error_swapgs
 	jmp  error_sti
+END(error_entry)
 	
        /* Reload gs selector with exception handling */
        /* edi:  new selector */ 
@@ -688,6 +704,7 @@ gs_change:     
 	swapgs
         popf
         ret
+ENDPROC(load_gs_index)
        
         .section __ex_table,"a"
         .align 8
@@ -741,6 +758,7 @@ ENTRY(kernel_thread)
 	UNFAKE_STACK_FRAME
 	ret
 	CFI_ENDPROC
+ENDPROC(kernel_thread)
 
 	
 child_rip:
@@ -754,6 +772,7 @@ child_rip:
 	# exit
 	xorl %edi, %edi
 	call do_exit
+ENDPROC(child_rip)
 
 /*
  * execve(). This function needs to use IRET, not SYSRET, to set up all state properly.
@@ -783,18 +802,23 @@ ENTRY(execve)
 	UNFAKE_STACK_FRAME
 	ret
 	CFI_ENDPROC
+ENDPROC(execve)
 
 ENTRY(page_fault)
 	errorentry do_page_fault
+END(page_fault)
 
 ENTRY(coprocessor_error)
 	zeroentry do_coprocessor_error
+END(coprocessor_error)
 
 ENTRY(simd_coprocessor_error)
 	zeroentry do_simd_coprocessor_error	
+END(simd_coprocessor_error)
 
 ENTRY(device_not_available)
 	zeroentry math_state_restore
+END(device_not_available)
 
 	/* runs on exception stack */
 ENTRY(debug)
@@ -804,6 +828,7 @@ ENTRY(debug)
 	paranoidentry do_debug
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(debug)
 
 	/* runs on exception stack */	
 ENTRY(nmi)
@@ -853,24 +878,27 @@ paranoid_schedule:
 	cli
 	jmp paranoid_userspace
 	CFI_ENDPROC
+END(nmi)
 
 ENTRY(int3)
 	zeroentry do_int3	
+END(int3)
 
 ENTRY(overflow)
 	zeroentry do_overflow
+END(overflow)
 
 ENTRY(bounds)
 	zeroentry do_bounds
+END(bounds)
 
 ENTRY(invalid_op)
 	zeroentry do_invalid_op	
+END(invalid_op)
 
 ENTRY(coprocessor_segment_overrun)
 	zeroentry do_coprocessor_segment_overrun
-
-ENTRY(reserved)
-	zeroentry do_reserved
+END(coprocessor_segment_overrun)
 
 	/* runs on exception stack */
 ENTRY(double_fault)
@@ -878,12 +906,15 @@ ENTRY(double_fault)
 	paranoidentry do_double_fault
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(double_fault)
 
 ENTRY(invalid_TSS)
 	errorentry do_invalid_TSS
+END(invalid_TSS)
 
 ENTRY(segment_not_present)
 	errorentry do_segment_not_present
+END(segment_not_present)
 
 	/* runs on exception stack */
 ENTRY(stack_segment)
@@ -891,18 +922,23 @@ ENTRY(stack_segment)
 	paranoidentry do_stack_segment
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(stack_segment)
 
 ENTRY(general_protection)
 	errorentry do_general_protection
+END(general_protection)
 
 ENTRY(alignment_check)
 	errorentry do_alignment_check
+END(alignment_check)
 
 ENTRY(divide_error)
 	zeroentry do_divide_error
+END(divide_error)
 
 ENTRY(spurious_interrupt_bug)
 	zeroentry do_spurious_interrupt_bug
+END(spurious_interrupt_bug)
 
 #ifdef CONFIG_X86_MCE
 	/* runs on exception stack */
@@ -913,10 +949,12 @@ ENTRY(machine_check)
 	paranoidentry do_machine_check
 	jmp paranoid_exit
 	CFI_ENDPROC
+END(machine_check)
 #endif
 
 ENTRY(call_debug)
        zeroentry do_call_debug
+END(call_debug)
 
 ENTRY(call_softirq)
 	movq %gs:pda_irqstackptr,%rax
@@ -929,4 +967,4 @@ ENTRY(call_softirq)
 	decl %gs:pda_irqcount
 	popq %r15
 	ret
-
+ENDPROC(call_softirq)
diff -Npru 2.6.13/include/linux/kallsyms.h 2.6.13-kallsyms/include/linux/kallsyms.h
--- 2.6.13/include/linux/kallsyms.h	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/include/linux/kallsyms.h	2005-03-16 12:24:42.000000000 +0100
@@ -19,6 +19,25 @@ const char *kallsyms_lookup(unsigned lon
 			    unsigned long *offset,
 			    char **modname, char *namebuf);
 
+#ifdef CONFIG_MODULES
+
+#if defined(Elf_Shdr) && defined(Elf_Sym)
+char kallsyms_elf_type(const Elf_Sym *sym,
+		       const Elf_Shdr *sechdrs,
+		       const char *secstrings);
+#endif
+
+struct module;
+void module_init_done(struct module *);
+
+unsigned long kallsyms_find_symname(struct module *, const char *);
+
+const char *kallsyms_get_ksymbol(struct module *,
+                                 unsigned long addr,
+                                 unsigned long *size,
+                                 unsigned long *offset);
+#endif
+
 /* Replace "%s" in format with address, if found */
 extern void __print_symbol(const char *fmt, unsigned long address);
 
@@ -64,4 +83,12 @@ do {						\
 	__print_symbol(fmt, addr);		\
 } while(0)
 
+#if defined(CONFIG_KALLSYMS) && !defined(CONFIG_KALLSYMS_TRADITIONAL)
+void kallsyms_early_init(void);
+void kallsyms_init_done(void);
+#else
+#define kallsyms_early_init() ((void)0)
+#define kallsyms_init_done() ((void)0)
+#endif
+
 #endif /*_LINUX_KALLSYMS_H*/
diff -Npru 2.6.13/include/linux/linkage.h 2.6.13-kallsyms/include/linux/linkage.h
--- 2.6.13/include/linux/linkage.h	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/include/linux/linkage.h	2005-03-16 12:24:42.000000000 +0100
@@ -33,6 +33,17 @@
   ALIGN; \
   name:
 
+#ifdef CONFIG_KALLSYMS
+#define ENDPROC(name) \
+  .type name, @function; \
+  END(name)
+#define END(name) \
+  .size name, .-name
+#else
+#define ENDPROC(name)
+#define END(name)
+#endif
+
 #endif
 
 #define NORET_TYPE    /**/
diff -Npru 2.6.13/include/linux/module.h 2.6.13-kallsyms/include/linux/module.h
--- 2.6.13/include/linux/module.h	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/include/linux/module.h	2005-09-01 11:32:12.000000000 +0200
@@ -301,7 +301,14 @@ struct module
 	/* We keep the symbol and string tables for kallsyms. */
 	Elf_Sym *symtab;
 	unsigned long num_symtab;
-	char *strtab;
+	const char *strtab;
+
+# ifndef CONFIG_KALLSYMS_TRADITIONAL
+	/* And also the sections and their string table. */
+	Elf_Shdr *sections;
+	unsigned long num_sections;
+	const char *shstrtab;
+# endif
 
 	/* Section attributes */
 	struct module_sect_attrs *sect_attrs;
diff -Npru 2.6.13/init/Kconfig 2.6.13-kallsyms/init/Kconfig
--- 2.6.13/init/Kconfig	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/init/Kconfig	2005-09-02 10:28:59.000000000 +0200
@@ -247,23 +247,40 @@ menuconfig EMBEDDED
           Only use this if you really know what you are doing.
 
 config KALLSYMS
-	 bool "Load all symbols for debugging/kksymoops" if EMBEDDED
-	 default y
-	 help
-	   Say Y here to let the kernel print out symbolic crash information and
-	   symbolic stack backtraces. This increases the size of the kernel
-	   somewhat, as all symbols have to be loaded into the kernel image.
+	bool "Load all symbols for debugging/kksymoops" if EMBEDDED
+	default y
+	help
+	  Say Y here to let the kernel print out symbolic crash information and
+	  symbolic stack backtraces. This increases the size of the kernel
+	  somewhat, as all symbols have to be loaded into the kernel image.
+
+config KALLSYMS_TRADITIONAL
+	bool "Traditional kallsyms symbol table format"
+	depends on KALLSYMS
+	default !MODULES
+	help
+	  Say N here if you want the kernel symbol table to be consistent with
+	  that loadable modules use (i.e. the ELF symbol table extracted from
+	  the kernel binary).
 
 config KALLSYMS_ALL
 	bool "Include all symbols in kallsyms"
 	depends on DEBUG_KERNEL && KALLSYMS
+	default DEBUG_KERNEL
 	help
-	   Normally kallsyms only contains the symbols of functions, for nicer
-	   OOPS messages.  Some debuggers can use kallsyms for other
-	   symbols too: say Y here to include all symbols, and you
-	   don't care about adding 300k to the size of your kernel.
-
-	   Say N.
+	  Normally kallsyms only contains the symbols of functions, for nicer
+	  OOPS messages.  Some debuggers can use kallsyms for other
+	  symbols too: say Y here to include all symbols, and you
+	  don't care about adding 300k to the size of your kernel.
+
+	  Say N.
+
+config KALLSYMS_STRIP_GENERATED
+	bool "Strip machine generated symbols from kallsyms" if KALLSYMS_ALL
+	depends on KALLSYMS && !KALLSYMS_TRADITIONAL
+	default y
+	help
+	  Say N if you want kallsyms to retain even machine generated symbols.
 
 config KALLSYMS_EXTRA_PASS
 	bool "Do an extra kallsyms pass"
diff -Npru 2.6.13/init/main.c 2.6.13-kallsyms/init/main.c
--- 2.6.13/init/main.c	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/init/main.c	2005-09-01 11:32:12.000000000 +0200
@@ -468,6 +468,7 @@ asmlinkage void __init start_kernel(void
 		   &unknown_bootoption);
 	sort_main_extable();
 	trap_init();
+	kallsyms_early_init();
 	rcu_init();
 	init_IRQ();
 	pidhash_init();
@@ -690,6 +691,7 @@ static int init(void * unused)
 	 * we're essentially up and running. Get rid of the
 	 * initmem segments and start the user-mode stuff..
 	 */
+	kallsyms_init_done();
 	free_initmem();
 	unlock_kernel();
 	system_state = SYSTEM_RUNNING;
diff -Npru 2.6.13/kernel/kallsyms.c 2.6.13-kallsyms/kernel/kallsyms.c
--- 2.6.13/kernel/kallsyms.c	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/kernel/kallsyms.c	2005-09-07 16:37:52.000000000 +0200
@@ -11,14 +11,15 @@
  *      Changed the compression method from stem compression to "table lookup"
  *      compression (see scripts/kallsyms.c for a more complete description)
  */
-#include <linux/kallsyms.h>
 #include <linux/module.h>
+#include <linux/kallsyms.h>
 #include <linux/init.h>
 #include <linux/seq_file.h>
 #include <linux/fs.h>
 #include <linux/err.h>
 #include <linux/proc_fs.h>
 #include <linux/mm.h>
+#include <asm/sections.h>
 
 #include <asm/sections.h>
 
@@ -28,15 +29,42 @@
 #define all_var 0
 #endif
 
-/* These will be re-linked against their real values during the second link stage */
-extern unsigned long kallsyms_addresses[] __attribute__((weak));
-extern unsigned long kallsyms_num_syms __attribute__((weak,section("data")));
-extern u8 kallsyms_names[] __attribute__((weak));
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
+extern const unsigned long kallsyms_addresses[];
+extern const unsigned long kallsyms_num_syms __attribute__((section("data")));
+extern const u8 kallsyms_names[];
 
-extern u8 kallsyms_token_table[] __attribute__((weak));
-extern u16 kallsyms_token_index[] __attribute__((weak));
+extern const u8 kallsyms_token_table[];
+extern const u16 kallsyms_token_index[];
+
+extern const unsigned long kallsyms_markers[];
+#else
+extern Elf_Shdr kallsyms_sections[];
+extern Elf_Sym kallsyms_symtab[];
+extern const char kallsyms_shstrtab[], kallsyms_strtab[];
+# ifdef CONFIG_MODULES
+struct module kallsyms_kernel_module = {
+	.module_core = _text,
+	.module_init = __init_begin,
+	.symtab = kallsyms_symtab,
+	.strtab = kallsyms_strtab,
+	.sections = kallsyms_sections,
+	.shstrtab = kallsyms_shstrtab
+};
+# else
+const void*const kallsyms_module_core = _text;
+const void*const kallsyms_module_init = __init_begin;
+size_t kallsyms_core_size = 0, kallsyms_init_size = 0;
+static size_t kallsyms_core_text_size, kallsyms_init_text_size;
+size_t kallsyms_num_sections = 0, kallsyms_num_symtab = 0;
+#  define KALLSYMS_VAR(mod, var) kallsyms_##var
+# endif
+# define kallsyms_num_syms KALLSYMS_VAR(&kallsyms_kernel_module, num_symtab)
+#endif
 
-extern unsigned long kallsyms_markers[] __attribute__((weak));
+#ifdef CONFIG_MODULES
+# define KALLSYMS_VAR(mod, var) (mod)->var
+#endif
 
 static inline int is_kernel_inittext(unsigned long addr)
 {
@@ -68,12 +96,36 @@ static inline int is_kernel(unsigned lon
 	return in_gate_area_no_task(addr);
 }
 
+static inline int within(unsigned long addr, const void *start, unsigned long size)
+{
+	return ((void *)addr >= start && (void *)addr < start + size);
+}
+
+#if defined(CONFIG_MODULES) || !defined(CONFIG_KALLSYMS_TRADITIONAL)
+# ifndef CONFIG_MODULES
+static inline
+#  define kallsyms_find_symname(m, n) kallsyms_find_symname(n)
+# endif
+unsigned long kallsyms_find_symname(
+	struct module *mod,
+	const char *name)
+{
+	unsigned long i;
+
+	for (i = 0; i < KALLSYMS_VAR(mod, num_symtab); i++)
+		if (strcmp(name, KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name) == 0)
+			return KALLSYMS_VAR(mod, symtab)[i].st_value;
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
 /* expand a compressed symbol data into the resulting uncompressed string,
    given the offset to where the symbol is in the compressed stream */
 static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
 {
 	int len, skipped_first = 0;
-	u8 *tptr, *data;
+	const u8 *tptr, *data;
 
 	/* get the compressed symbol length from the first symbol byte */
 	data = &kallsyms_names[off];
@@ -121,7 +173,7 @@ static char kallsyms_get_symbol_type(uns
  * kallsyms array */
 static unsigned int get_symbol_offset(unsigned long pos)
 {
-	u8 *name;
+	const u8 *name;
 	int i;
 
 	/* use the closest marker we have. We have markers every 256 positions,
@@ -137,10 +189,12 @@ static unsigned int get_symbol_offset(un
 
 	return name - kallsyms_names;
 }
+#endif
 
 /* Lookup the address for this symbol. Returns 0 if not found. */
 unsigned long kallsyms_lookup_name(const char *name)
 {
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
 	char namebuf[KSYM_NAME_LEN+1];
 	unsigned long i;
 	unsigned int off;
@@ -151,10 +205,78 @@ unsigned long kallsyms_lookup_name(const
 		if (strcmp(namebuf, name) == 0)
 			return kallsyms_addresses[i];
 	}
+#else
+	unsigned long kaddr = kallsyms_find_symname(&kallsyms_kernel_module, name);
+
+	if (kaddr)
+		return kaddr;
+#endif
 	return module_kallsyms_lookup_name(name);
 }
 EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
 
+#if defined(CONFIG_MODULES) || !defined(CONFIG_KALLSYMS_TRADITIONAL)
+/*
+ * 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)
+{
+#ifdef CONFIG_ARM
+	return str[0] == '$' && strchr("atd", str[1])
+	       && (str[2] == '\0' || str[2] == '.');
+#else
+	return 0;
+#endif
+}
+
+# ifndef CONFIG_MODULES
+static inline
+#  define kallsyms_get_ksymbol(m, a, s, o) kallsyms_get_ksymbol(a, s, o)
+# endif
+const char *kallsyms_get_ksymbol(struct module *mod,
+			       unsigned long addr,
+			       unsigned long *size,
+			       unsigned long *offset)
+{
+	unsigned long i, best = 0;
+	unsigned long nextval;
+
+	/* At worse, next value is at end of module */
+	if (within(addr, KALLSYMS_VAR(mod, module_init), KALLSYMS_VAR(mod, init_size)))
+		nextval = (unsigned long)KALLSYMS_VAR(mod, module_init) + KALLSYMS_VAR(mod, init_text_size);
+	else
+		nextval = (unsigned long)KALLSYMS_VAR(mod, module_core) + KALLSYMS_VAR(mod, core_text_size);
+
+	/* Scan for closest preceeding symbol, and next symbol. (ELF
+           starts real symbols at 1). */
+	for (i = 1; i < KALLSYMS_VAR(mod, num_symtab); i++) {
+		if (KALLSYMS_VAR(mod, symtab)[i].st_shndx == SHN_UNDEF)
+			continue;
+
+		/* We ignore unnamed symbols: they're uninformative
+		 * and inserted at a whim. */
+		if (KALLSYMS_VAR(mod, symtab)[i].st_value <= addr
+		    && KALLSYMS_VAR(mod, symtab)[i].st_value > KALLSYMS_VAR(mod, symtab)[best].st_value
+		    && *(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name) != '\0'
+		    && !is_arm_mapping_symbol(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name))
+			best = i;
+		if (KALLSYMS_VAR(mod, symtab)[i].st_value > addr
+		    && KALLSYMS_VAR(mod, symtab)[i].st_value < nextval
+		    && *(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name) != '\0'
+		    && !is_arm_mapping_symbol(KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[i].st_name))
+			nextval = KALLSYMS_VAR(mod, symtab)[i].st_value;
+	}
+
+	if (!best)
+		return NULL;
+
+	*size = nextval - KALLSYMS_VAR(mod, symtab)[best].st_value;
+	*offset = addr - KALLSYMS_VAR(mod, symtab)[best].st_value;
+	return KALLSYMS_VAR(mod, strtab) + KALLSYMS_VAR(mod, symtab)[best].st_name;
+}
+#endif
+
 /*
  * Lookup an address
  * - modname is set to NULL if it's in the kernel
@@ -167,18 +289,18 @@ const char *kallsyms_lookup(unsigned lon
 			    unsigned long *offset,
 			    char **modname, char *namebuf)
 {
-	unsigned long i, low, high, mid;
 	const char *msym;
 
-	/* This kernel should never had been booted. */
-	BUG_ON(!kallsyms_addresses);
-
 	namebuf[KSYM_NAME_LEN] = 0;
 	namebuf[0] = 0;
 
-	if ((all_var && is_kernel(addr)) ||
-	    (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) ||
-				is_kernel_extratext(addr)))) {
+	if (all_var
+	    ? is_kernel(addr)
+	    : is_kernel_text(addr)
+	      || is_kernel_inittext(addr)
+	      || is_kernel_extratext(addr)) {
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
+		unsigned long i, low, high, mid;
 		unsigned long symbol_end = 0;
 
 		/* do a binary search on the sorted kallsyms_addresses array */
@@ -219,6 +341,10 @@ const char *kallsyms_lookup(unsigned lon
 		*modname = NULL;
 		*offset = addr - kallsyms_addresses[low];
 		return namebuf;
+#else
+		*modname = NULL;
+		return kallsyms_get_ksymbol(&kallsyms_kernel_module, addr, symbolsize, offset);
+#endif
 	}
 
 	/* see if it's in a module */
@@ -236,30 +362,46 @@ void __print_symbol(const char *fmt, uns
 	const char *name;
 	unsigned long offset, size;
 	char namebuf[KSYM_NAME_LEN+1];
-	char buffer[sizeof("%s+%#lx/%#lx [%s]") + KSYM_NAME_LEN +
-		    2*(BITS_PER_LONG*3/10) + MODULE_NAME_LEN + 1];
 
 	name = kallsyms_lookup(address, &size, &offset, &modname, namebuf);
 
-	if (!name)
-		sprintf(buffer, "0x%lx", address);
-	else {
-		if (modname)
-			sprintf(buffer, "%s+%#lx/%#lx [%s]", name, offset,
-				size, modname);
-		else
-			sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+	if (!name) {
+		char addrstr[sizeof("0x%lx") + (BITS_PER_LONG*3/10)];
+
+		sprintf(addrstr, "0x%lx", address);
+		printk(fmt, addrstr);
+		return;
+	}
+
+	if (modname) {
+		/* This is pretty small. */
+		char buffer[sizeof("%s+%#lx/%#lx [%s]")
+			   + strlen(name) + 2*(BITS_PER_LONG*3/10)
+			   + strlen(modname)];
+
+		sprintf(buffer, "%s+%#lx/%#lx [%s]",
+			name, offset, size, modname);
+		printk(fmt, buffer);
+	} else {
+		char buffer[sizeof("%s+%#lx/%#lx")
+			   + strlen(name) + 2*(BITS_PER_LONG*3/10)];
+
+		sprintf(buffer, "%s+%#lx/%#lx", name, offset, size);
+		printk(fmt, buffer);
 	}
-	printk(fmt, buffer);
 }
 
 /* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
 struct kallsym_iter
 {
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
 	loff_t pos;
+#endif
 	struct module *owner;
 	unsigned long value;
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
 	unsigned int nameoff; /* If iterating in core kernel symbols */
+#endif
 	char type;
 	char name[KSYM_NAME_LEN+1];
 };
@@ -271,9 +413,9 @@ static void upcase_if_global(struct kall
 		iter->type += 'A' - 'a';
 }
 
-static int get_ksymbol_mod(struct kallsym_iter *iter)
+static int get_ksymbol_mod(struct kallsym_iter *iter, loff_t pos)
 {
-	iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms,
+	iter->owner = module_get_kallsym(pos,
 					 &iter->value,
 					 &iter->type, iter->name);
 	if (iter->owner == NULL)
@@ -283,6 +425,7 @@ static int get_ksymbol_mod(struct kallsy
 	return 1;
 }
 
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
 /* Returns space to next name. */
 static unsigned long get_ksymbol_core(struct kallsym_iter *iter)
 {
@@ -304,26 +447,87 @@ static void reset_iter(struct kallsym_it
 	iter->nameoff = get_symbol_offset(new_pos);
 	iter->pos = new_pos;
 }
+#else
+# define reset_iter(iter, new_pos) ((void)((iter)->name[0] = '\0'))
+#endif
 
 /* Returns false if pos at or past end of file. */
 static int update_iter(struct kallsym_iter *iter, loff_t pos)
 {
 	/* Module symbols can be accessed randomly. */
-	if (pos >= kallsyms_num_syms) {
-		iter->pos = pos;
-		return get_ksymbol_mod(iter);
-	}
+	if (pos >= kallsyms_num_syms)
+		return get_ksymbol_mod(iter, pos - kallsyms_num_syms);
 	
+#ifdef CONFIG_KALLSYMS_TRADITIONAL
 	/* If we're not on the desired position, reset to new position. */
 	if (pos != iter->pos)
 		reset_iter(iter, pos);
 
 	iter->nameoff += get_ksymbol_core(iter);
 	iter->pos++;
+#else
+	iter->owner = NULL;
+	iter->value = KALLSYMS_VAR(&kallsyms_kernel_module, symtab)[pos].st_value;
+	iter->type = KALLSYMS_VAR(&kallsyms_kernel_module, symtab)[pos].st_other;
+	strncpy(iter->name,
+		KALLSYMS_VAR(&kallsyms_kernel_module, strtab) + KALLSYMS_VAR(&kallsyms_kernel_module, symtab)[pos].st_name,
+		127);
+	upcase_if_global(iter);
+#endif
 
 	return 1;
 }
 
+#if defined(CONFIG_MODULES) || !defined(CONFIG_KALLSYMS_TRADITIONAL)
+# ifndef ARCH_SHF_SMALL
+#  define ARCH_SHF_SMALL 0
+# endif
+/* As per nm */
+# ifndef CONFIG_MODULES
+static inline __init
+# endif
+char kallsyms_elf_type(const Elf_Sym *sym,
+		     const Elf_Shdr *sechdrs,
+		     const char *secstrings)
+{
+	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
+		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
+			return 'v';
+		else
+			return 'w';
+	}
+	if (sym->st_shndx == SHN_UNDEF)
+		return 'U';
+	if (sym->st_shndx == SHN_ABS)
+		return 'a';
+	if (sym->st_shndx >= SHN_LORESERVE)
+		return '?';
+	if (sechdrs) {
+		if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
+			return 't';
+		if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC
+		    && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
+			if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
+				return 'r';
+			else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
+				return 'g';
+			else
+				return 'd';
+		}
+		if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
+			if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
+				return 's';
+			else
+				return 'b';
+		}
+		if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name,
+			    ".debug", strlen(".debug")) == 0)
+			return 'n';
+	}
+	return '?';
+}
+#endif
+
 static void *s_next(struct seq_file *m, void *p, loff_t *pos)
 {
 	(*pos)++;
@@ -417,4 +621,72 @@ static int __init kallsyms_init(void)
 }
 __initcall(kallsyms_init);
 
+#ifndef CONFIG_KALLSYMS_TRADITIONAL
+
+extern const size_t kallsyms_size_sections, kallsyms_size_symtab;
+extern const size_t kallsyms_size_shstrtab, kallsyms_size_strtab;
+
+void __init kallsyms_early_init() {
+	Elf_Shdr*section;
+	Elf_Sym*symbol;
+
+	KALLSYMS_VAR(&kallsyms_kernel_module, core_size) = _end - _text;
+	KALLSYMS_VAR(&kallsyms_kernel_module, core_text_size) = _etext - _stext;
+	KALLSYMS_VAR(&kallsyms_kernel_module, init_size) = __init_end - __init_begin;
+	KALLSYMS_VAR(&kallsyms_kernel_module, init_text_size) = _einittext - _sinittext;
+
+	BUG_ON(kallsyms_size_sections <= sizeof(*kallsyms_sections));
+	BUG_ON(kallsyms_size_sections % sizeof(*kallsyms_sections));
+	BUG_ON(kallsyms_size_shstrtab <= 0);
+	BUG_ON(*kallsyms_shstrtab);
+	BUG_ON(kallsyms_shstrtab[kallsyms_size_shstrtab - 1]);
+	for(section = kallsyms_sections + 1; (unsigned long)section < (unsigned long)kallsyms_sections + kallsyms_size_sections; ++section)
+		if(section->sh_name >= kallsyms_size_shstrtab)
+			section->sh_name = 0;
+	KALLSYMS_VAR(&kallsyms_kernel_module, num_sections) = kallsyms_size_sections / sizeof(*kallsyms_sections);
+
+	BUG_ON(kallsyms_size_symtab <= sizeof(*kallsyms_symtab));
+	BUG_ON(kallsyms_size_symtab % sizeof(*kallsyms_symtab));
+	BUG_ON(kallsyms_size_strtab <= 0);
+	BUG_ON(*kallsyms_strtab);
+	BUG_ON(kallsyms_strtab[kallsyms_size_strtab - 1]);
+	for(symbol = kallsyms_symtab + 1; (unsigned long)symbol < (unsigned long)kallsyms_symtab + kallsyms_size_symtab; ++symbol) {
+		if(symbol->st_name >= kallsyms_size_strtab)
+			symbol->st_name = 0;
+		symbol->st_other = kallsyms_elf_type(symbol, kallsyms_sections, kallsyms_shstrtab);
+	}
+	KALLSYMS_VAR(&kallsyms_kernel_module, num_symtab) = kallsyms_size_symtab / sizeof(*kallsyms_symtab);
+}
+
+
+void __init kallsyms_init_done() {
+# ifdef CONFIG_MODULES
+	module_init_done(&kallsyms_kernel_module);
+# else
+	Elf_Shdr*section;
+	const Elf_Sym*src;
+	Elf_Sym*dst;
+
+	for(section = kallsyms_sections + 1; (unsigned long)section < (unsigned long)kallsyms_sections + kallsyms_size_sections; ++section)
+		if(section->sh_addr >= (unsigned long)__init_begin
+		   && (section->sh_size
+		       ? section->sh_addr + section->sh_size - 1
+		       : section->sh_addr) < (unsigned long)__init_end)
+			section->sh_addr = 0;
+	for(src = dst = kallsyms_symtab + 1; (unsigned long)src < (unsigned long)kallsyms_symtab + kallsyms_size_symtab; ++src) {
+		if(!src->st_shndx || !src->st_name)
+			continue;
+		if(src->st_shndx < kallsyms_num_sections
+		   && !kallsyms_sections[src->st_shndx].sh_addr)
+			continue;
+		if(src != dst)
+			*dst = *src;
+		++dst;
+	}
+	kallsyms_num_symtab = dst - kallsyms_symtab;
+# endif
+}
+
+#endif /* CONFIG_KALLSYMS_TRADITIONAL */
+
 EXPORT_SYMBOL(__print_symbol);
diff -Npru 2.6.13/kernel/module.c 2.6.13-kallsyms/kernel/module.c
--- 2.6.13/kernel/module.c	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/kernel/module.c	2005-09-08 13:46:53.000000000 +0200
@@ -36,6 +36,7 @@
 #include <linux/stop_machine.h>
 #include <linux/device.h>
 #include <linux/string.h>
+#include <linux/kallsyms.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
@@ -1162,6 +1163,8 @@ static int __unlink_module(void *_mod)
 	return 0;
 }
 
+static void cleanup_kallsyms(struct module *);
+
 /* Free a module, remove from lists, etc (must hold module mutex). */
 static void free_module(struct module *mod)
 {
@@ -1176,6 +1179,8 @@ static void free_module(struct module *m
 	/* Module unload stuff */
 	module_unload_free(mod);
 
+	cleanup_kallsyms(mod);
+
 	/* This may be NULL, but that's OK */
 	module_free(mod, mod->module_init);
 	kfree(mod->args);
@@ -1424,49 +1429,9 @@ int is_exported(const char *name, const 
 	return 0;
 }
 
-/* As per nm */
-static char elf_type(const Elf_Sym *sym,
-		     Elf_Shdr *sechdrs,
-		     const char *secstrings,
-		     struct module *mod)
-{
-	if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
-		if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
-			return 'v';
-		else
-			return 'w';
-	}
-	if (sym->st_shndx == SHN_UNDEF)
-		return 'U';
-	if (sym->st_shndx == SHN_ABS)
-		return 'a';
-	if (sym->st_shndx >= SHN_LORESERVE)
-		return '?';
-	if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR)
-		return 't';
-	if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC
-	    && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) {
-		if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE))
-			return 'r';
-		else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
-			return 'g';
-		else
-			return 'd';
-	}
-	if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) {
-		if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL)
-			return 's';
-		else
-			return 'b';
-	}
-	if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name,
-		    ".debug", strlen(".debug")) == 0)
-		return 'n';
-	return '?';
-}
-
 static void add_kallsyms(struct module *mod,
-			 Elf_Shdr *sechdrs,
+			 const Elf_Ehdr *hdr,
+			 const Elf_Shdr *sechdrs,
 			 unsigned int symindex,
 			 unsigned int strindex,
 			 const char *secstrings)
@@ -1475,23 +1440,125 @@ static void add_kallsyms(struct module *
 
 	mod->symtab = (void *)sechdrs[symindex].sh_addr;
 	mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
-	mod->strtab = (void *)sechdrs[strindex].sh_addr;
+	mod->strtab = (const void *)sechdrs[strindex].sh_addr;
+
+	if (mod->num_symtab > 1
+	    && sechdrs[strindex].sh_size > 0
+	    && !*mod->strtab
+	    && !mod->strtab[sechdrs[strindex].sh_size - 1]) {
+		/* Set types up while we still have access to sections. */
+		for (i = 1; i < mod->num_symtab; i++) {
+			if (mod->symtab[i].st_name >= sechdrs[strindex].sh_size)
+				mod->symtab[i].st_name = 0;
+			mod->symtab[i].st_other
+				= kallsyms_elf_type(&mod->symtab[i], sechdrs, secstrings);
+		}
+	}
+	else {
+		mod->symtab = NULL;
+		mod->num_symtab = 0;
+		mod->strtab = NULL;
+	}
 
-	/* Set types up while we still have access to sections. */
-	for (i = 0; i < mod->num_symtab; i++)
-		mod->symtab[i].st_info
-			= elf_type(&mod->symtab[i], sechdrs, secstrings, mod);
+# ifndef CONFIG_KALLSYMS_TRADITIONAL
+	if (hdr->e_shnum > 1
+	    && sechdrs[hdr->e_shstrndx].sh_size > 0
+	    && !*secstrings
+	    && !secstrings[sechdrs[hdr->e_shstrndx].sh_size - 1]) {
+		if (hdr->e_shnum < PAGE_SIZE / sizeof(*sechdrs))
+			mod->sections = kmalloc(hdr->e_shnum * sizeof(*sechdrs), GFP_KERNEL);
+		else
+			mod->sections = vmalloc(hdr->e_shnum * sizeof(*sechdrs));
+	}
+	else
+		mod->sections = NULL;
+	if (mod->sections) {
+		mod->num_sections = hdr->e_shnum;
+		memset(mod->sections, 0, sizeof(*mod->sections));
+		mod->shstrtab = (const void *)sechdrs[hdr->e_shstrndx].sh_addr;
+		for (i = 1; i < mod->num_sections; ++i) {
+			mod->sections[i] = sechdrs[i];
+			if (mod->sections[i].sh_name >= sechdrs[hdr->e_shstrndx].sh_size)
+				mod->sections[i].sh_name = 0;
+			if (!(mod->sections[i].sh_flags & SHF_ALLOC))
+				mod->sections[i].sh_addr = 0;
+		}
+	}
+	else {
+		mod->num_sections = 0;
+		mod->shstrtab = NULL;
+	}
+#endif
+}
+
+static void cleanup_kallsyms(struct module *mod)
+{
+# ifndef CONFIG_KALLSYMS_TRADITIONAL
+	if (mod->num_sections) {
+		if (mod->num_sections < PAGE_SIZE / sizeof(*mod->sections))
+			kfree(mod->sections);
+		else
+			vfree(mod->sections);
+		mod->num_sections = 0;
+	}
+# endif
+	mod->num_symtab = 0;
 }
 #else
 static inline void add_kallsyms(struct module *mod,
-				Elf_Shdr *sechdrs,
+				const Elf_Ehdr *hdr,
+				const Elf_Shdr *sechdrs,
 				unsigned int symindex,
 				unsigned int strindex,
 				const char *secstrings)
 {
 }
+
+static inline void cleanup_kallsyms(struct module *mod)
+{
+}
 #endif /* CONFIG_KALLSYMS */
 
+#ifndef CONFIG_KALLSYMS
+static inline
+#endif
+void module_init_done(struct module *mod)
+{
+#ifdef CONFIG_KALLSYMS
+	if (mod->init_size) {
+		const Elf_Sym*src;
+		Elf_Sym*dst;
+# ifndef CONFIG_KALLSYMS_TRADITIONAL
+		Elf_Shdr*section;
+
+		for(section = mod->sections + 1; section < mod->sections + mod->num_sections; ++section)
+			if(section->sh_entsize & INIT_OFFSET_MASK)
+				section->sh_addr = 0;
+# endif
+		for(src = dst = mod->symtab + 1; src < mod->symtab + mod->num_symtab; ++src) {
+			if(!src->st_shndx || !src->st_name)
+				continue;
+# ifndef CONFIG_KALLSYMS_TRADITIONAL
+			if(src->st_shndx < mod->num_sections
+			   && !mod->sections[src->st_shndx].sh_addr)
+				continue;
+# else
+			if(src->st_value >= (unsigned long)mod->module_init
+			   && src->st_value < (unsigned long)mod->module_init + mod->init_size)
+				continue;
+# endif
+			if(src != dst)
+				*dst = *src;
+			++dst;
+		}
+		mod->num_symtab = dst - mod->symtab;
+	}
+#endif
+	mod->module_init = NULL;
+	mod->init_size = 0;
+	mod->init_text_size = 0;
+}
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
 static struct module *load_module(void __user *umod,
@@ -1529,7 +1596,8 @@ static struct module *load_module(void _
 	if (memcmp(hdr->e_ident, ELFMAG, 4) != 0
 	    || hdr->e_type != ET_REL
 	    || !elf_check_arch(hdr)
-	    || hdr->e_shentsize != sizeof(*sechdrs)) {
+	    || hdr->e_shentsize != sizeof(*sechdrs)
+	    || !hdr->e_shstrndx) {
 		err = -ENOEXEC;
 		goto free_hdr;
 	}
@@ -1553,6 +1621,10 @@ static struct module *load_module(void _
 
 		/* Internal symbols and strings. */
 		if (sechdrs[i].sh_type == SHT_SYMTAB) {
+			if (symindex) {
+				err = -ENOEXEC;
+				goto free_hdr;
+			}
 			symindex = i;
 			strindex = sechdrs[i].sh_link;
 			strtab = (char *)hdr + sechdrs[strindex].sh_offset;
@@ -1564,6 +1636,11 @@ static struct module *load_module(void _
 #endif
 	}
 
+	if (!symindex || !strindex) {
+		err = -ENOEXEC;
+		goto free_hdr;
+	}
+
 	modindex = find_sec(hdr, sechdrs, secstrings,
 			    ".gnu.linkonce.this_module");
 	if (!modindex) {
@@ -1595,9 +1672,14 @@ static struct module *load_module(void _
 	/* Don't keep modinfo section */
 	sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
 #ifdef CONFIG_KALLSYMS
+	mod->num_symtab = 0;
 	/* Keep symbol and string tables for decoding later. */
 	sechdrs[symindex].sh_flags |= SHF_ALLOC;
 	sechdrs[strindex].sh_flags |= SHF_ALLOC;
+# ifndef CONFIG_KALLSYMS_TRADITIONAL
+	mod->num_sections = 0;
+	sechdrs[hdr->e_shstrndx].sh_flags |= SHF_ALLOC;
+# endif
 #endif
 
 	/* Check module struct version now, before we try to use module. */
@@ -1773,7 +1855,7 @@ static struct module *load_module(void _
 	percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
 		       sechdrs[pcpuindex].sh_size);
 
-	add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
+	add_kallsyms(mod, hdr, sechdrs, symindex, strindex, secstrings);
 
 	err = module_finalize(hdr, sechdrs, mod);
 	if (err < 0)
@@ -1823,6 +1905,7 @@ static struct module *load_module(void _
 	module_arch_cleanup(mod);
  cleanup:
 	module_unload_free(mod);
+	cleanup_kallsyms(mod);
 	module_free(mod, mod->module_init);
  free_core:
 	module_free(mod, mod->module_core);
@@ -1928,9 +2011,7 @@ sys_init_module(void __user *umod,
 	/* Drop initial reference. */
 	module_put(mod);
 	module_free(mod, mod->module_init);
-	mod->module_init = NULL;
-	mod->init_size = 0;
-	mod->init_text_size = 0;
+	module_init_done(mod);
 	up(&module_mutex);
 
 	return 0;
@@ -1942,58 +2023,6 @@ static inline int within(unsigned long a
 }
 
 #ifdef CONFIG_KALLSYMS
-/*
- * 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)
-{
-	return str[0] == '$' && strchr("atd", str[1]) 
-	       && (str[2] == '\0' || str[2] == '.');
-}
-
-static const char *get_ksymbol(struct module *mod,
-			       unsigned long addr,
-			       unsigned long *size,
-			       unsigned long *offset)
-{
-	unsigned int i, best = 0;
-	unsigned long nextval;
-
-	/* At worse, next value is at end of module */
-	if (within(addr, mod->module_init, mod->init_size))
-		nextval = (unsigned long)mod->module_init+mod->init_text_size;
-	else 
-		nextval = (unsigned long)mod->module_core+mod->core_text_size;
-
-	/* Scan for closest preceeding symbol, and next symbol. (ELF
-           starts real symbols at 1). */
-	for (i = 1; i < mod->num_symtab; i++) {
-		if (mod->symtab[i].st_shndx == SHN_UNDEF)
-			continue;
-
-		/* We ignore unnamed symbols: they're uninformative
-		 * and inserted at a whim. */
-		if (mod->symtab[i].st_value <= addr
-		    && mod->symtab[i].st_value > mod->symtab[best].st_value
-		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
-			best = i;
-		if (mod->symtab[i].st_value > addr
-		    && mod->symtab[i].st_value < nextval
-		    && *(mod->strtab + mod->symtab[i].st_name) != '\0'
-		    && !is_arm_mapping_symbol(mod->strtab + mod->symtab[i].st_name))
-			nextval = mod->symtab[i].st_value;
-	}
-
-	if (!best)
-		return NULL;
-
-	*size = nextval - mod->symtab[best].st_value;
-	*offset = addr - mod->symtab[best].st_value;
-	return mod->strtab + mod->symtab[best].st_name;
-}
-
 /* For kallsyms to ask for address resolution.  NULL means not found.
    We don't lock, as this is used for oops resolution and races are a
    lesser concern. */
@@ -2008,7 +2037,7 @@ const char *module_address_lookup(unsign
 		if (within(addr, mod->module_init, mod->init_size)
 		    || within(addr, mod->module_core, mod->core_size)) {
 			*modname = mod->name;
-			return get_ksymbol(mod, addr, size, offset);
+			return kallsyms_get_ksymbol(mod, addr, size, offset);
 		}
 	}
 	return NULL;
@@ -2025,7 +2054,7 @@ struct module *module_get_kallsym(unsign
 	list_for_each_entry(mod, &modules, list) {
 		if (symnum < mod->num_symtab) {
 			*value = mod->symtab[symnum].st_value;
-			*type = mod->symtab[symnum].st_info;
+			*type = mod->symtab[symnum].st_other;
 			strncpy(namebuf,
 				mod->strtab + mod->symtab[symnum].st_name,
 				127);
@@ -2038,16 +2067,6 @@ struct module *module_get_kallsym(unsign
 	return NULL;
 }
 
-static unsigned long mod_find_symname(struct module *mod, const char *name)
-{
-	unsigned int i;
-
-	for (i = 0; i < mod->num_symtab; i++)
-		if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0)
-			return mod->symtab[i].st_value;
-	return 0;
-}
-
 /* Look for this name: can be of form module:name. */
 unsigned long module_kallsyms_lookup_name(const char *name)
 {
@@ -2059,11 +2078,11 @@ unsigned long module_kallsyms_lookup_nam
 	if ((colon = strchr(name, ':')) != NULL) {
 		*colon = '\0';
 		if ((mod = find_module(name)) != NULL)
-			ret = mod_find_symname(mod, colon+1);
+			ret = kallsyms_find_symname(mod, colon+1);
 		*colon = ':';
 	} else {
 		list_for_each_entry(mod, &modules, list)
-			if ((ret = mod_find_symname(mod, name)) != 0)
+			if ((ret = kallsyms_find_symname(mod, name)) != 0)
 				break;
 	}
 	return ret;
diff -Npru 2.6.13/Makefile 2.6.13-kallsyms/Makefile
--- 2.6.13/Makefile	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/Makefile	2005-09-08 15:35:32.000000000 +0200
@@ -161,15 +161,19 @@ LOCALVERSION = $(subst $(space),, \
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)$(LOCALVERSION)
 
+HOSTARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
+				   -e s/arm.*/arm/ -e s/sa110/arm/ \
+				   -e s/s390x/s390/ -e s/parisc64/parisc/ )
+
 # SUBARCH tells the usermode build what the underlying arch is.  That is set
 # first, and if a usermode build is happening, the "ARCH=um" on the command
 # line overrides the setting of ARCH below.  If a native build is happening,
 # then ARCH is assigned, getting whatever value it gets normally, and 
 # SUBARCH is subsequently ignored.
 
-SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \
-				  -e s/arm.*/arm/ -e s/sa110/arm/ \
-				  -e s/s390x/s390/ -e s/parisc64/parisc/ )
+ifeq ($(SUBARCH),)
+SUBARCH         := $(if $(filter-out um,$(ARCH)),$(ARCH),$(HOSTARCH))
+endif
 
 # Cross compiling and selecting different set of gcc/bin-utils
 # ---------------------------------------------------------------------------
@@ -191,7 +195,7 @@ SUBARCH := $(shell uname -m | sed -e s/i
 # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
 
 ARCH		?= $(SUBARCH)
-CROSS_COMPILE	?=
+CROSS_COMPILE	?= $(if $(filter-out $(ARCH) $(SUBARCH),$(HOSTARCH)),$(SUBARCH)-linux-)
 
 # Architecture as present in compile.h
 UTS_MACHINE := $(ARCH)
@@ -325,6 +329,7 @@ NM		= $(CROSS_COMPILE)nm
 STRIP		= $(CROSS_COMPILE)strip
 OBJCOPY		= $(CROSS_COMPILE)objcopy
 OBJDUMP		= $(CROSS_COMPILE)objdump
+READELF		= $(CROSS_COMPILE)readelf
 AWK		= awk
 GENKSYMS	= scripts/genksyms/genksyms
 DEPMOD		= /sbin/depmod
@@ -700,24 +705,109 @@ endef
 
 # Generate .S file with all kernel symbols
 quiet_cmd_kallsyms = KSYM    $@
-      cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
-                     $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
 
-.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
+ifdef CONFIG_KALLSYMS_TRADITIONAL
+
+cmd_kallsyms = { test $* -eq 0 || $(NM) -n $<; } | $(KALLSYMS) $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) >$@
+
+kallsyms-strip-ext :=
+
+else
+
+cmd_kallsyms = { test $* -eq 0 || $(NM) -n $<; } | $(KALLSYMS) -$$(expr $* + 1) >$@
+
+kallsyms-strip-src := $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(srctree)/$(KALLSYMS))
+kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(wildcard $(srctree)/arch/$(ARCH)/kallsyms))
+kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_ALL),,data)
+kallsyms-strip-src := $(strip $(kallsyms-strip-src))
+kallsyms-strip-ext := $(if $(kallsyms-strip-src),.stripped)
+
+quiet_cmd_ktab = KTAB    $@
+define cmd_ktab
+	if [ $* -eq 0 ]; then \
+		echo "placeholder" >$@; \
+	else \
+		rm -f $@; \
+		$(READELF) -SW $< | while read idx name type addr offs size more; do \
+			if [ "$(suffix $@)" = "$$name" ]; then \
+				tail -c +$$((0x$$offs+1)) <$< | head -c $$((0x$$size)) >$@; \
+				break; \
+			fi; \
+		done; \
+		test -s $@; \
+	fi
+endef
+
+quiet_cmd_kshdr = KSHDR   $@
+define cmd_kshdr
+	if [ $* -eq 0 ]; then \
+		echo "placeholder" >$@; \
+	else \
+		nsect= ;: grab this from the first decimal number; \
+		osect= ;: grab this from the first hexadecimal number; \
+		for i in $$($(READELF) -S $< | egrep '^[^]\[()]*$$'); \
+		do \
+			test -z "$$nsect" && nsect=$$(echo $${i%:*} | egrep '^[[:digit:]]+$$'); \
+			test -z "$$osect" && osect=$$(echo $${i%:*} | egrep '^0[xX][[:xdigit:]]+$$'); \
+		done; \
+		zsect= ;: grab this from the last number that is followed by a unit specification; \
+		for i in $$($(READELF) -h $< | egrep ':[[:space:]]+[[:digit:]]+[[:space:]]+\(.*\)'); \
+		do \
+			val=$$(echo $$i | egrep '^([[:digit:]]+|0[xX][[:xdigit:]]+)$$'); \
+			test -n "$$val" && zsect=$$val; \
+		done; \
+		tail -c +$$((osect+1)) <$< | head -c $$((nsect*zsect)) >$@; \
+	fi
+endef
+
+quiet_cmd_kstrip = STRIP   $<
+cmd_kstrip = $(OBJCOPY) $(addprefix --strip-symbols ,$(filter %.strip,$^)) -w $< $@
+
+.tmp_kallsyms%.symtab: .tmp_vmlinux%$(kallsyms-strip-ext)
+	$(call cmd,ktab)
+
+.tmp_kallsyms%.strtab: .tmp_vmlinux%$(kallsyms-strip-ext)
+	$(call cmd,ktab)
+
+.tmp_kallsyms%.sections: .tmp_vmlinux%$(kallsyms-strip-ext)
+	$(call cmd,kshdr)
+
+.tmp_kallsyms%.shstrtab: .tmp_vmlinux%$(kallsyms-strip-ext)
+	$(call cmd,ktab)
+
+.tmp_vmlinux%.stripped: .tmp_vmlinux% $(addsuffix .strip,$(kallsyms-strip-src)) .config
+	$(call cmd,kstrip)
+
+close := )
+data.strip: .tmp_vmlinux1 .config
+	$(Q)$(NM) $< | sed -n 's,[[:xdigit:]]\+[[:space:]]\+[^tT][[:space:]]\+\(.*\),\1,p' \
+		| while read i; do case $$i in \
+			$(addsuffix $(close);;, \
+				$(shell cat $(addsuffix .strip,$(filter $(srctree)/%,$(kallsyms-strip-src))) /dev/null \
+				        | sed 's,\([;|&<>()$$\\]\),\\\1,g')) \
+			*) echo $$i;; \
+		esac; done >$@
+
+endif # CONFIG_KALLSYMS_TRADITIONAL
+
+$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): AFLAGS+=-Wa,--strip-local-absolute
+$(foreach n,0 1 2 3,.tmp_kallsyms$(n).o): %.o: %.S $(if $(CONFIG_KALLSYMS_TRADITIONAL),,%.symtab %.strtab %.sections %.shstrtab) scripts FORCE
 	$(call if_changed_dep,as_o_S)
 
-.tmp_kallsyms%.S: .tmp_vmlinux% $(KALLSYMS)
+.tmp_kallsyms%.S: .tmp_vmlinux%$(kallsyms-strip-ext) $(KALLSYMS) .config
 	$(call cmd,kallsyms)
 
-# .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version
-.tmp_vmlinux1: $(vmlinux-lds) $(vmlinux-all) FORCE
-	$(call if_changed_rule,ksym_ld)
+.tmp_vmlinux0$(kallsyms-strip-ext):
+	$(Q)echo "placeholder" >$@
 
-.tmp_vmlinux2: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms1.o FORCE
-	$(call if_changed,vmlinux__)
+.tmp_vmlinux1: .tmp_kallsyms0.o
+.tmp_vmlinux2: .tmp_kallsyms1.o
+.tmp_vmlinux3: .tmp_kallsyms2.o
 
-.tmp_vmlinux3: $(vmlinux-lds) $(vmlinux-all) .tmp_kallsyms2.o FORCE
-	$(call if_changed,vmlinux__)
+.tmp_vmlinux%: LDFLAGS_vmlinux += -S
+# .tmp_vmlinux1 must be complete except kallsyms, so update vmlinux version
+.tmp_vmlinux%: $(vmlinux-lds) $(vmlinux-all) FORCE
+	$(if $(filter 1,$*),$(call if_changed_rule,ksym_ld),$(call if_changed,vmlinux__))
 
 # Needs to visit scripts/ before $(KALLSYMS) can be used.
 $(KALLSYMS): scripts ;
diff -Npru 2.6.13/scripts/genksyms/genksyms.c 2.6.13-kallsyms/scripts/genksyms/genksyms.c
--- 2.6.13/scripts/genksyms/genksyms.c	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/scripts/genksyms/genksyms.c	2005-03-18 17:54:12.000000000 +0100
@@ -43,7 +43,7 @@ FILE *debugfile;
 int cur_line = 1;
 char *cur_filename, *output_directory;
 
-int flag_debug, flag_dump_defs, flag_warnings;
+int flag_debug, flag_dump_defs, flag_warnings, flag_inline_asm;
 
 static int errors;
 static int nsyms;
@@ -457,8 +457,16 @@ export_symbol(const char *name)
       if (flag_dump_defs)
 	fputs(">\n", debugfile);
 
-      /* Used as a linker script. */
-      printf("__crc_%s = 0x%08lx ;\n", name, crc);
+      if (!flag_inline_asm)
+	{
+	  /* Used as a linker script. */
+	  printf("__crc_%s = 0x%08lx ;\n", name, crc);
+	}
+      else
+	{
+	  /* Used as inline assembly. */
+	  printf("__asm__(\".equiv __crc_%s, 0x%08lx\");\n", name, crc);
+	}
     }
 }
 
@@ -529,6 +537,7 @@ main(int argc, char **argv)
 
 #ifdef __GNU_LIBRARY__
   struct option long_opts[] = {
+    {"asm", 0, 0, 'a'},
     {"debug", 0, 0, 'd'},
     {"warnings", 0, 0, 'w'},
     {"quiet", 0, 0, 'q'},
@@ -538,13 +547,16 @@ main(int argc, char **argv)
     {0, 0, 0, 0}
   };
 
-  while ((o = getopt_long(argc, argv, "dwqVDk:p:",
+  while ((o = getopt_long(argc, argv, "adwqVDk:p:",
 			  &long_opts[0], NULL)) != EOF)
 #else  /* __GNU_LIBRARY__ */
-  while ((o = getopt(argc, argv, "dwqVDk:p:")) != EOF)
+  while ((o = getopt(argc, argv, "adwqVDk:p:")) != EOF)
 #endif /* __GNU_LIBRARY__ */
     switch (o)
       {
+      case 'a':
+	flag_inline_asm = 1;
+	break;
       case 'd':
 	flag_debug++;
 	break;
diff -Npru 2.6.13/scripts/kallsyms.c 2.6.13-kallsyms/scripts/kallsyms.c
--- 2.6.13/scripts/kallsyms.c	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/scripts/kallsyms.c	2005-09-07 15:57:16.000000000 +0200
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <limits.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. */
@@ -67,6 +68,7 @@ struct sym_entry {
 
 static struct sym_entry *table;
 static int size, cnt;
+static long stage;
 static unsigned long long _stext, _etext, _sinittext, _einittext, _sextratext, _eextratext;
 static int all_symbols = 0;
 static char symbol_prefix_char = '\0';
@@ -94,7 +96,7 @@ unsigned char best_table_len[256];
 static void
 usage(void)
 {
-	fprintf(stderr, "Usage: kallsyms [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
+	fprintf(stderr, "Usage: kallsyms [stage] [--all-symbols] [--symbol-prefix=<prefix char>] < in.map > out.S\n");
 	exit(1);
 }
 
@@ -105,8 +107,12 @@ usage(void)
 static inline int
 is_arm_mapping_symbol(const char *str)
 {
+#if defined(ARCH_arm) || defined(ARCH_arm26)
 	return str[0] == '$' && strchr("atd", str[1])
 	       && (str[2] == '\0' || str[2] == '.');
+#else
+	return 0;
+#endif
 }
 
 static int
@@ -176,13 +182,6 @@ symbol_valid(struct sym_entry *s)
 	 * specified so exclude them to get a stable symbol list.
 	 */
 	static char *special_symbols[] = {
-		"kallsyms_addresses",
-		"kallsyms_num_syms",
-		"kallsyms_names",
-		"kallsyms_markers",
-		"kallsyms_token_table",
-		"kallsyms_token_index",
-
 	/* Exclude linker generated symbols which vary between passes */
 		"_SDA_BASE_",		/* ppc */
 		"_SDA2_BASE_",		/* ppc */
@@ -214,7 +213,8 @@ symbol_valid(struct sym_entry *s)
 	}
 
 	/* Exclude symbols which vary between passes. */
-	if (strstr(s->sym + offset, "_compiled."))
+	if (strstr(s->sym + offset, "_compiled.") ||
+	    strncmp(s->sym + offset, "__compound_literal.", 19) == 0)
 		return 0;
 
 	for (i = 0; special_symbols[i]; i++)
@@ -298,7 +298,42 @@ write_src(void)
 	printf("#define ALGN .align 4\n");
 	printf("#endif\n");
 
-	printf(".data\n");
+	printf(".section .rodata, \"a\"\n");
+
+	if (stage) {
+		static struct {
+			const char*name;
+			unsigned writeable:1;
+			unsigned aligned:1;
+		} const what[] = {
+			{"sections", 1, 1},
+			{"symtab",   1, 1},
+			{"strtab",   0, 0},
+			{"shstrtab", 0, 0}
+		};
+
+		for (i = 0; i < sizeof(what)/sizeof(*what); ++i) {
+			if (what[i].writeable)
+				printf(".data\n");
+			printf(".globl kallsyms_%s, kallsyms_size_%s\n", what[i].name, what[i].name);
+			if (what[i].aligned)
+				printf("\tALGN\n");
+			printf("kallsyms_%s:\n", what[i].name);
+			printf(".incbin \".tmp_kallsyms%ld.%s\"\n", labs(stage) - 1, what[i].name);
+			printf(".equ __kallsyms_size_%s, . - kallsyms_%s\n", what[i].name, what[i].name);
+			if (what[i].writeable)
+				printf(".previous\n");
+			printf("\n");
+		}
+		printf("\tALGN\n");
+		for (i = 0; i < sizeof(what)/sizeof(*what); ++i) {
+			printf("kallsyms_size_%s:\n", what[i].name);
+			printf("\tPTR\t__kallsyms_size_%s\n", what[i].name);
+		}
+		printf("\n");
+	}
+	if (stage < 0)
+		return;
 
 	output_label("kallsyms_addresses");
 	valid = 0;
@@ -703,25 +738,28 @@ static void optimize_token_table(void)
 int
 main(int argc, char **argv)
 {
-	if (argc >= 2) {
-		int i;
-		for (i = 1; i < argc; i++) {
-			if(strcmp(argv[i], "--all-symbols") == 0)
-				all_symbols = 1;
-			else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
-				char *p = &argv[i][16];
-				/* skip quote */
-				if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\''))
-					p++;
-				symbol_prefix_char = *p;
-			} else
-				usage();
-		}
-	} else if (argc != 1)
-		usage();
+	int i;
+
+	for (i = 1; i < argc; i++) {
+		if(strcmp(argv[i], "--all-symbols") == 0)
+			all_symbols = 1;
+		else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
+			char *p = &argv[i][16];
+
+			/* skip quote */
+			if ((*p == '"' || *p == '\'') && p[2] == *p)
+				p++;
+			symbol_prefix_char = *p;
+		} else if ((stage = strtol(argv[i], argv + i, 0)) == 0
+		           || stage >= LONG_MAX
+		           || stage <= LONG_MIN
+		           || *argv[i])
+			usage();
+	}
 
 	read_map(stdin);
-	optimize_token_table();
+	if (stage >= 0 && cnt)
+		optimize_token_table();
 	write_src();
 
 	return 0;
diff -Npru 2.6.13/scripts/kallsyms.strip 2.6.13-kallsyms/scripts/kallsyms.strip
--- 2.6.13/scripts/kallsyms.strip	1970-01-01 01:00:00.000000000 +0100
+++ 2.6.13-kallsyms/scripts/kallsyms.strip	2005-03-21 16:34:09.000000000 +0100
@@ -0,0 +1,18 @@
+<*>
+__compound_literal[$.][0-9]*
+__crc_[a-zA-Z_]*
+__exitcall_[a-zA-Z_]*
+__func__[$.][0-9]*
+__FUNCTION__[$.][0-9]*
+gcc[0-9]_compiled[$.]
+__initcall_[a-zA-Z_]*
+__kcrctab_[a-zA-Z_]*
+__kstrtab_[a-zA-Z_]*
+__ksymtab_[a-zA-Z_]*
+__mod_[a-zA-Z_]*[0-9]
+__module_depends
+__param_[a-zA-Z_]*
+__pci_fixup_[A-Z]*
+__PRETTY_FUNCTION__[$.][0-9]*
+__setup_[a-zA-Z_0-9]*
+____versions
diff -Npru 2.6.13/scripts/Makefile 2.6.13-kallsyms/scripts/Makefile
--- 2.6.13/scripts/Makefile	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/scripts/Makefile	2005-03-21 10:50:21.000000000 +0100
@@ -8,6 +8,7 @@
 # conmakehash:	 Create arrays for initializing the kernel console tables
 
 hostprogs-$(CONFIG_KALLSYMS)     += kallsyms
+HOSTCFLAGS_kallsyms.o := -D ARCH_$(SUBARCH)
 hostprogs-$(CONFIG_LOGO)         += pnmtologo
 hostprogs-$(CONFIG_VT)           += conmakehash
 hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash
diff -Npru 2.6.13/scripts/Makefile.build 2.6.13-kallsyms/scripts/Makefile.build
--- 2.6.13/scripts/Makefile.build	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/scripts/Makefile.build	2005-09-07 15:19:18.000000000 +0200
@@ -153,23 +153,26 @@ else
 #   are done.
 # o otherwise, we calculate symbol versions using the good old
 #   genksyms on the preprocessed source and postprocess them in a way
-#   that they are usable as a linker script
-# o generate <file>.o from .tmp_<file>.o using the linker to
-#   replace the unresolved symbols __crc_exported_symbol with
-#   the actual value of the checksum generated by genksyms
+#   that they are usable as assembly source
+# o recompile <file>.o from <file>.c forcing inclusion of assembler
+#   directives defining the actual values of __crc_*, followed by
+#   objcopy-ing them to force these symbols to be local to permit
+#   stripping them during the final module linking stage.
 
 cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
 cmd_modversions =							\
 	if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then	\
-		$(CPP) -D__GENKSYMS__ $(c_flags) $<			\
-		| $(GENKSYMS)						\
-		> $(@D)/.tmp_$(@F:.o=.ver);				\
-									\
-		$(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) 		\
-			-T $(@D)/.tmp_$(@F:.o=.ver);			\
-		rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver);	\
+		if $(CPP) -D__GENKSYMS__ $(c_flags) $<			\
+		   | $(GENKSYMS) -a > $(@D)/.tmp_$(@F:.o=.ver)		\
+		   && $(CC) $(c_flags) -c -w -include $(@D)/.tmp_$(@F:.o=.ver) -o $@ $< \
+		   && $(OBJCOPY) -L '__crc_*' -w $@; then		\
+			rm -f $(@D)/.tmp_$(@F);				\
+		else							\
+			rm -f $@; exit 1;				\
+		fi;							\
 	else								\
 		mv $(@D)/.tmp_$(@F) $@;					\
+		rm -f $(@D)/.tmp_$(@F:.o=.ver);				\
 	fi;
 endif
 
@@ -180,6 +183,12 @@ define rule_cc_o_c
 	$(cmd_cc_o_c);							  \
 	$(cmd_modversions)						  \
 	scripts/basic/fixdep $(depfile) $@ '$(subst ','\'',$(cmd_cc_o_c))' > $(@D)/.$(@F).tmp;  \
+	if [ -r $(@D)/.tmp_$(@F:.o=.ver) ]; then			  \
+		echo >> $(@D)/.$(@F).tmp;				  \
+		echo '$@: $(GENKSYMS)' >> $(@D)/.$(@F).tmp;		  \
+		echo '$(GENKSYMS):: ;' >> $(@D)/.$(@F).tmp;		  \
+		rm $(@D)/.tmp_$(@F:.o=.ver);				  \
+	fi;								  \
 	rm -f $(depfile);						  \
 	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd
 endef
diff -Npru 2.6.13/scripts/Makefile.lib 2.6.13-kallsyms/scripts/Makefile.lib
--- 2.6.13/scripts/Makefile.lib	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/scripts/Makefile.lib	2005-09-01 11:32:13.000000000 +0200
@@ -7,6 +7,8 @@
 comma   := ,
 empty   :=
 space   := $(empty) $(empty)
+open    := (
+close   := )
 
 # Backward compatibility - to be removed...
 extra-y	+= $(EXTRA_TARGETS)
diff -Npru 2.6.13/scripts/Makefile.modinst 2.6.13-kallsyms/scripts/Makefile.modinst
--- 2.6.13/scripts/Makefile.modinst	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/scripts/Makefile.modinst	2005-09-01 11:32:13.000000000 +0200
@@ -17,7 +17,8 @@ __modinst: $(modules)
 	@:
 
 quiet_cmd_modules_install = INSTALL $@
-      cmd_modules_install = mkdir -p $(2); cp $@ $(2)
+      cmd_modules_install = mkdir -p $(2); \
+			    cp $(firstword $(wildcard $@s) $@) $(2)/$(basename $(@F)).ko
 
 # Modules built outside the kernel source tree go into extra by default
 INSTALL_MOD_DIR ?= extra
diff -Npru 2.6.13/scripts/Makefile.modpost 2.6.13-kallsyms/scripts/Makefile.modpost
--- 2.6.13/scripts/Makefile.modpost	2005-08-29 01:41:01.000000000 +0200
+++ 2.6.13-kallsyms/scripts/Makefile.modpost	2005-09-07 17:45:27.000000000 +0200
@@ -40,9 +40,33 @@ include scripts/Makefile.lib
 
 symverfile := $(objtree)/Module.symvers
 
+ifdef CONFIG_KALLSYMS
+
+ifdef CONFIG_KALLSYMS_TRADITIONAL
+
+kallsyms-strip-src :=
+
+else
+
+kallsyms-strip-src := $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(srctree)/scripts/kallsyms.strip)
+kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_STRIP_GENERATED),$(wildcard $(srctree)/arch/$(ARCH)/kallsyms.strip))
+# binutils up to at least 2.15 do not permit stripping symbols by name while
+# retaining those that are needed by relocations...
+# kallsyms-strip-src += $(if $(CONFIG_KALLSYMS_ALL),,data)
+
+endif
+
+ko := $(if $(strip $(kallsyms-strip-src)),.kos,.ko)
+
+else
+
+ko := .kos
+
+endif
+
 # Step 1), find all modules listed in $(MODVERDIR)/
 __modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
-modules   := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o)))
+modules   := $(patsubst %.o,%$(ko), $(wildcard $(__modules:.ko=.o)))
 
 _modpost: $(modules)
 
@@ -57,12 +81,12 @@ quiet_cmd_modpost = MODPOST
 	$(filter-out FORCE,$^)
 
 .PHONY: __modpost
-__modpost: $(wildcard vmlinux) $(modules:.ko=.o) FORCE
+__modpost: $(wildcard vmlinux) $(modules:$(ko)=.o) FORCE
 	$(call cmd,modpost)
 
 # Declare generated files as targets for modpost
 $(symverfile):         __modpost ;
-$(modules:.ko=.mod.c): __modpost ;
+$(modules:$(ko)=.mod.c): __modpost ;
 
 
 # Step 5), compile all *.mod.c files
@@ -74,19 +98,51 @@ quiet_cmd_cc_o_c = CC      $@
       cmd_cc_o_c = $(CC) $(c_flags) $(CFLAGS_MODULE)	\
 		   -c -o $@ $<
 
-$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE
+$(modules:$(ko)=.mod.o): %.mod.o: %.mod.c FORCE
 	$(call if_changed_dep,cc_o_c)
 
-targets += $(modules:.ko=.mod.o)
+targets += $(modules:$(ko)=.mod.o)
 
 # Step 6), final link of the modules
 quiet_cmd_ld_ko_o = LD [M]  $@
       cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ 		\
 			  $(filter-out FORCE,$^)
 
-$(modules): %.ko :%.o %.mod.o FORCE
+ifeq ($(ko),.ko)
+
+$(modules): %.ko: %.o %.mod.o FORCE
+	$(Q)rm -f $@s
+	$(call if_changed,ld_ko_o)
+
+else
+
+$(patsubst %$(ko),%.ko,$(modules)): %.ko: %.o %.mod.o FORCE
 	$(call if_changed,ld_ko_o)
 
+# Step 7), strip as many symbols from the modules as feasible
+quiet_cmd_strip_kos_ko = STRIP   $<
+ifdef CONFIG_KALLSYMS
+cmd_strip_kos_ko = $(OBJCOPY) --strip-debug $(addprefix --strip-symbols ,$(filter %.strip,$^)) -w $< $@
+else
+cmd_strip_kos_ko = $(OBJCOPY) --strip-debug --strip-unneeded $< $@
+endif
+
+%$(ko): %.ko $(filter %.strip,$(kallsyms-strip-src)) $(if $(filter data,$(kallsyms-strip-src)),.data_%.strip) FORCE
+	$(call if_changed,strip_kos_ko)
+
+.PRECIOUS: .data_%.strip
+.data_%.strip: %.ko .config
+	$(Q)$(NM) $< | sed -n 's,[[:xdigit:]]\+[[:space:]]\+[^tT][[:space:]]\+\(.*\),\1,p' \
+		| while read i; do case $$i in \
+			$(addsuffix $(close);;,$(shell cat $(filter $(srctree)/%,$(kallsyms-strip-src)) \
+				| sed 's,\([;|&<>()$$\\]\),\\\1,g')) \
+			*) echo $$i;; \
+		esac; done >$@
+
+targets += $(patsubst %$(ko),%.ko,$(modules))
+
+endif
+
 targets += $(modules)
 
 

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] new kallsyms approach
  2005-09-08 14:58 [PATCH] new kallsyms approach Jan Beulich
@ 2005-09-09  3:47 ` Andi Kleen
  2005-09-09 10:18   ` Jan Beulich
  0 siblings, 1 reply; 3+ messages in thread
From: Andi Kleen @ 2005-09-09  3:47 UTC (permalink / raw)
  To: Jan Beulich; +Cc: linux-kernel

"Jan Beulich" <JBeulich@novell.com> writes:


> This patch provides al alternative to the pre-exisiting kallsyms code.
> That code, from a kernel debugger perspective at least, suffers from
> incomplete information, making it impossible to
> (a) disambiguate multiple static functions of the same name (in
> different
> source files),
> (b) determine a complete set of attributes for a symbol (namely, the
> symbol's size, but also its type, which gets converted to an nm-like
> one-
> character representation), and
> (c) retain full section information

I don't think it's a good idea to have two different ways
to do kallsyms. Either we should always use your new
way in standard KALLSYMS or not do it at all.

The major decision factor is how much bloat it adds.
Can you post before/after numbers of binary size? 

If the difference is >5% or so - are there ways to recover
the difference? 

-Andi




^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] new kallsyms approach
  2005-09-09  3:47 ` Andi Kleen
@ 2005-09-09 10:18   ` Jan Beulich
  0 siblings, 0 replies; 3+ messages in thread
From: Jan Beulich @ 2005-09-09 10:18 UTC (permalink / raw)
  To: Andi Kleen; +Cc: linux-kernel

>I don't think it's a good idea to have two different ways
>to do kallsyms. Either we should always use your new
>way in standard KALLSYMS or not do it at all.

I agree, but I wanted to retain the old mechanism not the least because
of the space constraints you mention.

>The major decision factor is how much bloat it adds.
>Can you post before/after numbers of binary size? 

i386 vmlinux KALLSYMS_ALL=n: old=5782934 new=6106675 (5.60% increase)
i386 vmlinux KALLSYMS_ALL=y: old=6049118 new=6524411 (7.85% increase)
x86-64 vmlinux KALLSYMS_ALL=n: old=8593125 new=8962128 (4.30%
increase)
x86-64 vmlinux KALLSYMS_ALL=y: old=8797853 new=9117704 (3.64%
increase)

I shall note additionally that not using KALLSYMS_ALL with the new
approach increases the build time somewhat because the stripping of the
data symbols in this scheme is rather inefficient (a binutils limitation
as I would call it). KALLSYMS_ALL=y, however, is mostly suited for
kernel debugging, while KALLSYMS_ALL=n seems the best choice if just
caring about symbolic stack traces, which seems to be another argument
for keeping both mechanisms.

>If the difference is >5% or so - are there ways to recover
>the difference? 

There are certainly ways, but I'm not sure how much they would cost.
One thing would be to teach the linker to not only optimize the section
string table, but also the (normal) symbol string one. Decreasing the
symbol table size might be more difficult - only st_size and only on
64-bit archs seems to lend itself to reduction (as any symbol's size can
clearly be expected to be less than 4G). But that would result in
alignment problems, so I don't think that'd be a good idea either.

Jan

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2005-09-09 10:17 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-09-08 14:58 [PATCH] new kallsyms approach Jan Beulich
2005-09-09  3:47 ` Andi Kleen
2005-09-09 10:18   ` Jan Beulich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox