@@ -45,36 +45,44 @@ type BlockRange = Range<SectionAddress>;
45
45
46
46
type InsCheck = dyn Fn ( Ins ) -> bool ;
47
47
48
+ /// Stop searching for prologue/epilogue sequences if the next instruction
49
+ /// is a branch or uses r0 or r1.
50
+ fn is_end_of_seq ( next : & Ins ) -> bool {
51
+ next. is_branch ( )
52
+ || next
53
+ . defs ( )
54
+ . iter ( )
55
+ . chain ( next. uses ( ) . iter ( ) )
56
+ . any ( |a| matches ! ( a, ppc750cl:: Argument :: GPR ( ppc750cl:: GPR ( 0 | 1 ) ) ) )
57
+ }
58
+
48
59
#[ inline( always) ]
49
60
fn check_sequence (
50
61
section : & ObjSection ,
51
62
addr : SectionAddress ,
52
63
ins : Option < Ins > ,
53
64
sequence : & [ ( & InsCheck , & InsCheck ) ] ,
54
65
) -> Result < bool > {
55
- let mut found = false ;
66
+ let ins = ins
67
+ . or_else ( || disassemble ( section, addr. address ) )
68
+ . with_context ( || format ! ( "Failed to disassemble instruction at {addr:#010X}" ) ) ?;
56
69
for & ( first, second) in sequence {
57
- let Some ( ins) = ins. or_else ( || disassemble ( section, addr. address ) ) else {
58
- continue ;
59
- } ;
60
70
if !first ( ins) {
61
71
continue ;
62
72
}
63
- let Some ( next) = disassemble ( section, addr. address + 4 ) else {
64
- continue ;
65
- } ;
66
- if second ( next)
67
- // Also check the following instruction, in case the scheduler
68
- // put something in between.
69
- || ( !next. is_branch ( )
70
- && matches ! ( disassemble( section, addr. address + 8 ) , Some ( ins) if second( ins) ) )
71
- {
72
- found = true ;
73
- break ;
73
+ let mut current_addr = addr. address + 4 ;
74
+ while let Some ( next) = disassemble ( section, current_addr) {
75
+ if second ( next) {
76
+ return Ok ( true ) ;
77
+ }
78
+ if is_end_of_seq ( & next) {
79
+ // If we hit a branch or an instruction that uses r0 or r1, stop searching.
80
+ break ;
81
+ }
82
+ current_addr += 4 ;
74
83
}
75
84
}
76
-
77
- Ok ( found)
85
+ Ok ( false )
78
86
}
79
87
80
88
fn check_prologue_sequence (
@@ -97,7 +105,11 @@ fn check_prologue_sequence(
97
105
// stw r0, d(r1)
98
106
ins. op == Opcode :: Stw && ins. field_rs ( ) == 0 && ins. field_ra ( ) == 1
99
107
}
100
- check_sequence ( section, addr, ins, & [ ( & is_stwu, & is_mflr) , ( & is_mflr, & is_stw) ] )
108
+ check_sequence ( section, addr, ins, & [
109
+ ( & is_stwu, & is_mflr) ,
110
+ ( & is_mflr, & is_stw) ,
111
+ ( & is_mflr, & is_stwu) ,
112
+ ] )
101
113
}
102
114
103
115
impl FunctionSlices {
@@ -148,7 +160,28 @@ impl FunctionSlices {
148
160
}
149
161
if check_prologue_sequence ( section, addr, Some ( ins) ) ? {
150
162
if let Some ( prologue) = self . prologue {
151
- if prologue != addr && prologue != addr - 4 {
163
+ let invalid_seq = if prologue == addr {
164
+ false
165
+ } else if prologue > addr {
166
+ true
167
+ } else {
168
+ // Check if any instructions between the prologue and this address
169
+ // are branches or use r0 or r1.
170
+ let mut current_addr = prologue. address + 4 ;
171
+ loop {
172
+ if current_addr == addr. address {
173
+ break false ;
174
+ }
175
+ let next = disassemble ( section, current_addr) . with_context ( || {
176
+ format ! ( "Failed to disassemble {current_addr:#010X}" )
177
+ } ) ?;
178
+ if is_end_of_seq ( & next) {
179
+ break true ;
180
+ }
181
+ current_addr += 4 ;
182
+ }
183
+ } ;
184
+ if invalid_seq {
152
185
bail ! ( "Found multiple functions inside a symbol: {:#010X} and {:#010X}. Check symbols.txt?" , prologue, addr)
153
186
}
154
187
} else {
0 commit comments