Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
6162c729
Commit
6162c729
authored
Feb 05, 2003
by
Anton Blanchard
Browse files
Options
Browse Files
Download
Plain Diff
Merge samba.org:/scratch/anton/linux-2.5_ppc64_up
into samba.org:/scratch/anton/sfr
parents
cd7fc258
11ee811c
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
59 additions
and
135 deletions
+59
-135
arch/ppc64/kernel/module.c
arch/ppc64/kernel/module.c
+59
-135
No files found.
arch/ppc64/kernel/module.c
View file @
6162c729
...
@@ -136,6 +136,20 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
...
@@ -136,6 +136,20 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr,
return
relocs
*
sizeof
(
struct
ppc64_stub_entry
);
return
relocs
*
sizeof
(
struct
ppc64_stub_entry
);
}
}
/* Undefined symbols which refer to .funcname, hack to funcname */
static
void
dedotify
(
Elf64_Sym
*
syms
,
unsigned
int
numsyms
,
char
*
strtab
)
{
unsigned
int
i
;
for
(
i
=
1
;
i
<
numsyms
;
i
++
)
{
if
(
syms
[
i
].
st_shndx
==
SHN_UNDEF
)
{
char
*
name
=
strtab
+
syms
[
i
].
st_name
;
if
(
name
[
0
]
==
'.'
)
memmove
(
name
,
name
+
1
,
strlen
(
name
));
}
}
}
int
module_frob_arch_sections
(
Elf64_Ehdr
*
hdr
,
int
module_frob_arch_sections
(
Elf64_Ehdr
*
hdr
,
Elf64_Shdr
*
sechdrs
,
Elf64_Shdr
*
sechdrs
,
char
*
secstrings
,
char
*
secstrings
,
...
@@ -143,7 +157,7 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
...
@@ -143,7 +157,7 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
{
{
unsigned
int
i
;
unsigned
int
i
;
/* Find .toc and .stubs sections */
/* Find .toc and .stubs sections
, symtab and strtab
*/
for
(
i
=
1
;
i
<
hdr
->
e_shnum
;
i
++
)
{
for
(
i
=
1
;
i
<
hdr
->
e_shnum
;
i
++
)
{
char
*
p
;
char
*
p
;
if
(
strcmp
(
secstrings
+
sechdrs
[
i
].
sh_name
,
".stubs"
)
==
0
)
if
(
strcmp
(
secstrings
+
sechdrs
[
i
].
sh_name
,
".stubs"
)
==
0
)
...
@@ -154,6 +168,12 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
...
@@ -154,6 +168,12 @@ int module_frob_arch_sections(Elf64_Ehdr *hdr,
/* We don't handle .init for the moment: rename to _init */
/* We don't handle .init for the moment: rename to _init */
while
((
p
=
strstr
(
secstrings
+
sechdrs
[
i
].
sh_name
,
".init"
)))
while
((
p
=
strstr
(
secstrings
+
sechdrs
[
i
].
sh_name
,
".init"
)))
p
[
0
]
=
'_'
;
p
[
0
]
=
'_'
;
if
(
sechdrs
[
i
].
sh_type
==
SHT_SYMTAB
)
dedotify
((
void
*
)
hdr
+
sechdrs
[
i
].
sh_offset
,
sechdrs
[
i
].
sh_size
/
sizeof
(
Elf64_Sym
),
(
void
*
)
hdr
+
sechdrs
[
sechdrs
[
i
].
sh_link
].
sh_offset
);
}
}
if
(
!
me
->
arch
.
stubs_section
||
!
me
->
arch
.
toc_section
)
{
if
(
!
me
->
arch
.
stubs_section
||
!
me
->
arch
.
toc_section
)
{
printk
(
"%s: doesn't contain .toc or .stubs.
\n
"
,
me
->
name
);
printk
(
"%s: doesn't contain .toc or .stubs.
\n
"
,
me
->
name
);
...
@@ -175,6 +195,14 @@ int apply_relocate(Elf64_Shdr *sechdrs,
...
@@ -175,6 +195,14 @@ int apply_relocate(Elf64_Shdr *sechdrs,
return
-
ENOEXEC
;
return
-
ENOEXEC
;
}
}
/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
gives the value maximum span in an instruction which uses a signed
offset) */
static
inline
unsigned
long
my_r2
(
Elf64_Shdr
*
sechdrs
,
struct
module
*
me
)
{
return
sechdrs
[
me
->
arch
.
toc_section
].
sh_addr
+
0x8000
;
}
/* Both low and high 16 bits are added as SIGNED additions, so if low
/* Both low and high 16 bits are added as SIGNED additions, so if low
16 bits has high bit set, high 16 bits must be adjusted. These
16 bits has high bit set, high 16 bits must be adjusted. These
macros do that (stolen from binutils). */
macros do that (stolen from binutils). */
...
@@ -183,10 +211,10 @@ int apply_relocate(Elf64_Shdr *sechdrs,
...
@@ -183,10 +211,10 @@ int apply_relocate(Elf64_Shdr *sechdrs,
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
#define PPC_HA(v) PPC_HI ((v) + 0x8000)
/* Patch stub to reference function and correct r2 value. */
/* Patch stub to reference function and correct r2 value. */
static
inline
int
create_stub
(
struct
ppc64_stub_entry
*
entry
,
static
inline
int
create_stub
(
Elf64_Shdr
*
sechdrs
,
unsigned
long
my_r2
,
struct
ppc64_stub_entry
*
entry
,
unsigned
long
func
,
struct
ppc64_opd_entry
*
opd
,
unsigned
long
r2
)
struct
module
*
me
)
{
{
Elf64_Half
*
loc1
,
*
loc2
;
Elf64_Half
*
loc1
,
*
loc2
;
long
reladdr
;
long
reladdr
;
...
@@ -196,72 +224,32 @@ static inline int create_stub(struct ppc64_stub_entry *entry,
...
@@ -196,72 +224,32 @@ static inline int create_stub(struct ppc64_stub_entry *entry,
loc1
=
(
Elf64_Half
*
)
&
entry
->
jump
[
2
];
loc1
=
(
Elf64_Half
*
)
&
entry
->
jump
[
2
];
loc2
=
(
Elf64_Half
*
)
&
entry
->
jump
[
6
];
loc2
=
(
Elf64_Half
*
)
&
entry
->
jump
[
6
];
/* Stub uses address relative to r2, which is set to the TOC +
/* Stub uses address relative to r2. */
0x8000. */
reladdr
=
(
unsigned
long
)
entry
-
my_r2
(
sechdrs
,
me
);
reladdr
=
(
unsigned
long
)
entry
-
my_r2
;
if
(
reladdr
>
0x7FFFFFFF
||
reladdr
<
-
(
0x80000000L
))
{
if
(
reladdr
>
0x7FFFFFFF
||
reladdr
<
-
(
0x80000000L
))
{
printk
(
"Address %p of stub out of range of %p.
\n
"
,
printk
(
"
%s:
Address %p of stub out of range of %p.
\n
"
,
(
void
*
)
reladdr
,
(
void
*
)
my_r2
);
me
->
name
,
(
void
*
)
reladdr
,
(
void
*
)
my_r2
);
return
0
;
return
0
;
}
}
DEBUGP
(
"Stub %p get data from reladdr %li
\n
"
,
entry
,
reladdr
);
DEBUGP
(
"Stub %p get data from reladdr %li
\n
"
,
entry
,
reladdr
);
*
loc1
=
PPC_HA
(
reladdr
);
*
loc1
=
PPC_HA
(
reladdr
);
*
loc2
=
PPC_LO
(
reladdr
);
*
loc2
=
PPC_LO
(
reladdr
);
entry
->
opd
.
funcaddr
=
func
;
entry
->
opd
.
funcaddr
=
opd
->
funcaddr
;
entry
->
opd
.
r2
=
r2
;
entry
->
opd
.
r2
=
opd
->
r2
;
DEBUGP
(
"Stub: %08X %08X %08X %08X %08X %08X %08X: %p %p
\n
"
,
((
unsigned
int
*
)
entry
->
jump
)[
0
],
((
unsigned
int
*
)
entry
->
jump
)[
1
],
((
unsigned
int
*
)
entry
->
jump
)[
2
],
((
unsigned
int
*
)
entry
->
jump
)[
3
],
((
unsigned
int
*
)
entry
->
jump
)[
4
],
((
unsigned
int
*
)
entry
->
jump
)[
5
],
((
unsigned
int
*
)
entry
->
jump
)[
6
],
(
void
*
)
entry
->
opd
.
funcaddr
,
(
void
*
)
entry
->
opd
.
r2
);
return
1
;
return
1
;
}
}
/* Given ".function" reference, return address of "function" opd entry */
/* Create stub to jump to function described in this OPD: we need the
static
struct
ppc64_opd_entry
*
find_function
(
const
char
*
name
,
stub to set up the TOC ptr (r2) for the function. */
Elf64_Shdr
*
sechdrs
,
unsigned
int
symindex
,
const
char
*
strtab
,
struct
module
*
me
,
struct
kernel_symbol_group
**
ksg
)
{
unsigned
long
val
;
if
(
name
[
0
]
!=
'.'
)
return
0
;
val
=
find_symbol_internal
(
sechdrs
,
symindex
,
strtab
,
name
+
1
,
me
,
ksg
);
DEBUGP
(
"Function %s is at %p
\n
"
,
name
+
1
,
(
void
*
)
val
);
return
(
void
*
)
val
;
}
/* r2 is the TOC pointer: it actually points 0x8000 into the TOC (this
gives the value maximum span in an instruction which uses a signed
offset) */
static
inline
unsigned
long
my_r2
(
Elf64_Shdr
*
sechdrs
,
struct
module
*
me
)
{
return
sechdrs
[
me
->
arch
.
toc_section
].
sh_addr
+
0x8000
;
}
/* Create stub for this OPD address */
static
unsigned
long
stub_for_addr
(
Elf64_Shdr
*
sechdrs
,
static
unsigned
long
stub_for_addr
(
Elf64_Shdr
*
sechdrs
,
unsigned
long
addr
,
unsigned
long
opdaddr
,
unsigned
long
r2
,
struct
module
*
me
)
struct
module
*
me
)
{
{
struct
ppc64_stub_entry
*
stubs
;
struct
ppc64_stub_entry
*
stubs
;
struct
ppc64_opd_entry
*
opd
=
(
void
*
)
opdaddr
;
unsigned
int
i
,
num_stubs
;
unsigned
int
i
,
num_stubs
;
DEBUGP
(
"Looking for stub for %p
\n
"
,
(
void
*
)
addr
);
num_stubs
=
sechdrs
[
me
->
arch
.
stubs_section
].
sh_size
/
sizeof
(
*
stubs
);
num_stubs
=
sechdrs
[
me
->
arch
.
stubs_section
].
sh_size
/
sizeof
(
*
stubs
);
/* Find this stub, or if that fails, the next avail. entry */
/* Find this stub, or if that fails, the next avail. entry */
...
@@ -269,50 +257,23 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
...
@@ -269,50 +257,23 @@ static unsigned long stub_for_addr(Elf64_Shdr *sechdrs,
for
(
i
=
0
;
stubs
[
i
].
opd
.
funcaddr
;
i
++
)
{
for
(
i
=
0
;
stubs
[
i
].
opd
.
funcaddr
;
i
++
)
{
BUG_ON
(
i
>=
num_stubs
);
BUG_ON
(
i
>=
num_stubs
);
if
(
stubs
[
i
].
opd
.
funcaddr
==
addr
)
{
if
(
stubs
[
i
].
opd
.
funcaddr
==
opd
->
funcaddr
)
DEBUGP
(
"Reusing stub %u (%p) for %p
\n
"
,
i
,
&
stubs
[
i
],
(
void
*
)
addr
);
return
(
unsigned
long
)
&
stubs
[
i
];
return
(
unsigned
long
)
&
stubs
[
i
];
}
}
}
DEBUGP
(
"Here for %p
\n
"
,
(
void
*
)
addr
);
if
(
!
create_stub
(
&
stubs
[
i
],
my_r2
(
sechdrs
,
me
),
addr
,
r2
))
if
(
!
create_stub
(
sechdrs
,
&
stubs
[
i
],
opd
,
me
))
return
(
unsigned
long
)
-
EINVAL
;
return
0
;
DEBUGP
(
"CREATED stub %u for %p
\n
"
,
i
,
(
void
*
)
addr
);
return
(
unsigned
long
)
&
stubs
[
i
];
return
(
unsigned
long
)
&
stubs
[
i
];
}
}
/* We need a stub to set the toc ptr when we make external calls. */
static
unsigned
long
do_stub_call
(
Elf64_Shdr
*
sechdrs
,
const
char
*
strtab
,
unsigned
int
symindex
,
void
*
location
,
const
char
*
funcname
,
struct
module
*
me
)
{
struct
ppc64_opd_entry
*
opd
;
struct
kernel_symbol_group
*
ksg
;
DEBUGP
(
"Doing stub for %lu (%s)
\n
"
,
(
unsigned
long
)
location
,
funcname
);
opd
=
find_function
(
funcname
,
sechdrs
,
symindex
,
strtab
,
me
,
&
ksg
);
if
(
!
opd
)
{
printk
(
"%s: Can't find function `%s'
\n
"
,
me
->
name
,
funcname
);
return
(
unsigned
long
)
-
ENOENT
;
}
return
stub_for_addr
(
sechdrs
,
opd
->
funcaddr
,
opd
->
r2
,
me
);
}
/* We expect a noop next: if it is, replace it with instruction to
/* We expect a noop next: if it is, replace it with instruction to
restore r2. */
restore r2. */
static
int
restore_r2
(
u32
*
instruction
)
static
int
restore_r2
(
u32
*
instruction
,
struct
module
*
me
)
{
{
if
(
*
instruction
!=
0x60000000
)
{
if
(
*
instruction
!=
0x60000000
)
{
printk
(
"Expect noop after relocate, got %08x
\n
"
,
*
instruction
);
printk
(
"%s: Expect noop after relocate, got %08x
\n
"
,
me
->
name
,
*
instruction
);
return
0
;
return
0
;
}
}
*
instruction
=
0xe8410028
;
/* ld r2,40(r1) */
*
instruction
=
0xe8410028
;
/* ld r2,40(r1) */
...
@@ -346,31 +307,18 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
...
@@ -346,31 +307,18 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
strtab
+
sym
->
st_name
,
(
unsigned
long
)
sym
->
st_value
,
strtab
+
sym
->
st_name
,
(
unsigned
long
)
sym
->
st_value
,
(
long
)
rela
[
i
].
r_addend
);
(
long
)
rela
[
i
].
r_addend
);
/* REL24 references to (external) .function won't
resolve; deal with that below */
if
(
!
sym
->
st_value
&&
ELF64_R_TYPE
(
rela
[
i
].
r_info
)
!=
R_PPC_REL24
)
{
printk
(
"%s: Unknown symbol %s (index %u)
\n
"
,
me
->
name
,
strtab
+
sym
->
st_name
,
sym
->
st_shndx
);
return
-
ENOENT
;
}
/* `Everything is relative'. */
/* `Everything is relative'. */
value
=
sym
->
st_value
+
rela
[
i
].
r_addend
;
value
=
sym
->
st_value
+
rela
[
i
].
r_addend
;
switch
(
ELF64_R_TYPE
(
rela
[
i
].
r_info
))
{
switch
(
ELF64_R_TYPE
(
rela
[
i
].
r_info
))
{
case
R_PPC64_ADDR32
:
case
R_PPC64_ADDR32
:
/* Simply set it */
/* Simply set it */
DEBUGP
(
"Setting location %p to 32-bit value %u
\n
"
,
location
,
(
unsigned
int
)
value
);
*
(
u32
*
)
location
=
value
;
*
(
u32
*
)
location
=
value
;
break
;
break
;
case
R_PPC64_ADDR64
:
case
R_PPC64_ADDR64
:
/* Simply set it */
/* Simply set it */
*
(
unsigned
long
*
)
location
=
value
;
*
(
unsigned
long
*
)
location
=
value
;
DEBUGP
(
"Setting location %p to 64-bit value %p
\n
"
,
location
,
(
void
*
)
value
);
break
;
break
;
case
R_PPC64_TOC
:
case
R_PPC64_TOC
:
...
@@ -381,37 +329,31 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
...
@@ -381,37 +329,31 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
/* Subtact TOC pointer */
/* Subtact TOC pointer */
value
-=
my_r2
(
sechdrs
,
me
);
value
-=
my_r2
(
sechdrs
,
me
);
if
((
value
&
3
)
!=
0
||
value
+
0x8000
>
0xffff
)
{
if
((
value
&
3
)
!=
0
||
value
+
0x8000
>
0xffff
)
{
DEBUGP
(
"%s: bad TOC16_DS relocation (%lu)
\n
"
,
printk
(
"%s: bad TOC16_DS relocation (%lu)
\n
"
,
me
->
name
,
value
);
me
->
name
,
value
);
return
-
ENOEXEC
;
return
-
ENOEXEC
;
}
}
*
((
uint16_t
*
)
location
)
*
((
uint16_t
*
)
location
)
=
(
*
((
uint16_t
*
)
location
)
&
~
0xfffc
)
=
(
*
((
uint16_t
*
)
location
)
&
~
0xfffc
)
|
(
value
&
0xfffc
);
|
(
value
&
0xfffc
);
DEBUGP
(
"Modifying location %p by TOC (%p) => %i
\n
"
,
location
,
(
void
*
)
my_r2
(
sechdrs
,
me
),
*
(
uint16_t
*
)
location
);
break
;
break
;
case
R_PPC_REL24
:
case
R_PPC_REL24
:
/* FIXME: Handle weak symbols here --RR */
/* FIXME: Handle weak symbols here --RR */
if
(
sym
->
st_shndx
==
SHN_UNDEF
)
{
if
(
sym
->
st_shndx
==
SHN_UNDEF
)
{
value
=
do_stub_call
(
sechdrs
,
strtab
,
/* External: go via stub */
symindex
,
location
,
value
=
stub_for_addr
(
sechdrs
,
value
,
me
);
strtab
+
sym
->
st_name
,
me
);
if
(
!
value
)
if
(
IS_ERR
((
void
*
)
value
))
return
-
ENOENT
;
return
value
;
if
(
!
restore_r2
((
u32
*
)
location
+
1
,
me
))
value
+=
rela
[
i
].
r_addend
;
if
(
!
restore_r2
((
u32
*
)
location
+
1
))
return
-
ENOEXEC
;
return
-
ENOEXEC
;
}
}
/* Convert value to relative */
/* Convert value to relative */
value
-=
(
unsigned
long
)
location
;
value
-=
(
unsigned
long
)
location
;
if
(
value
+
0x2000000
>
0x3ffffff
||
(
value
&
3
)
!=
0
){
if
(
value
+
0x2000000
>
0x3ffffff
||
(
value
&
3
)
!=
0
){
printk
(
"
REL24 relocation
%li out of range!
\n
"
,
printk
(
"
%s: REL24
%li out of range!
\n
"
,
(
long
int
)
value
);
me
->
name
,
(
long
int
)
value
);
return
-
ENOEXEC
;
return
-
ENOEXEC
;
}
}
...
@@ -422,7 +364,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
...
@@ -422,7 +364,8 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
break
;
break
;
default:
default:
printk
(
"Unknown ADD relocation: %lu
\n
"
,
printk
(
"%s: Unknown ADD relocation: %lu
\n
"
,
me
->
name
,
(
unsigned
long
)
ELF64_R_TYPE
(
rela
[
i
].
r_info
));
(
unsigned
long
)
ELF64_R_TYPE
(
rela
[
i
].
r_info
));
return
-
ENOEXEC
;
return
-
ENOEXEC
;
}
}
...
@@ -439,25 +382,6 @@ int module_finalize(const Elf_Ehdr *hdr,
...
@@ -439,25 +382,6 @@ int module_finalize(const Elf_Ehdr *hdr,
const
Elf_Shdr
*
sechdrs
,
const
Elf_Shdr
*
sechdrs
,
struct
module
*
me
)
struct
module
*
me
)
{
{
struct
ppc64_stub_entry
*
stubs
;
unsigned
int
i
;
/* Here is where we copy the OPD entry into the stub: we don't
do it ealier in case it's actually in the same module, and
hasn't been relocated yet. */
stubs
=
(
void
*
)
sechdrs
[
me
->
arch
.
stubs_section
].
sh_addr
;
for
(
i
=
0
;
stubs
[
i
].
opd
.
funcaddr
;
i
++
)
{
struct
ppc64_opd_entry
*
opd
;
/* We mark opd pointers by setting r2 to 0: otherwise
it's a function pointer already. */
if
(
stubs
[
i
].
opd
.
r2
==
0
)
{
/* We put the opd entry ptr in the funcaddr member. */
opd
=
(
void
*
)
stubs
[
i
].
opd
.
funcaddr
;
stubs
[
i
].
opd
=
*
opd
;
}
}
sort_ex_table
(
me
->
extable
.
entry
,
sort_ex_table
(
me
->
extable
.
entry
,
me
->
extable
.
entry
+
me
->
extable
.
num_entries
);
me
->
extable
.
entry
+
me
->
extable
.
num_entries
);
return
0
;
return
0
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment