aboutsummaryrefslogtreecommitdiff
path: root/ld/testsuite/lib/ld-lib.exp
blob: 6c0c7f1daa084c56ca4cf75a15dcb63d44b09142 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
#
# default_ld_version 
#	extract and print the version number of ld
#
proc default_ld_version { ld } {
    global host_triplet

    if { [which $ld] == 0 } then {
	perror "$ld does not exist"
	exit 1
    }
    
    catch "exec $ld --version" tmp
    set tmp [prune_warnings $tmp]
    regexp "\[^\n\]* (cygnus-|)(\[-0-9.a-zA-Z-\]+)\[\r\n\].*" $tmp version cyg number
    if [info exists number] then {
	clone_output "$ld $number\n"
    }
}

#
# default_ld_relocate 
#	link an object using relocation
#
proc default_ld_relocate { ld target objects } {
    global HOSTING_EMU
    global host_triplet
    
    if { [which $ld] == 0 } then {
	perror "$ld does not exist"
	return 0
    }
    
    verbose -log "$ld $HOSTING_EMU -o $target -r $objects"
    
    catch "exec $ld $HOSTING_EMU -o $target -r $objects" exec_output
    set exec_output [prune_warnings $exec_output]
    if [string match "" $exec_output] then {
	return 1
    } else {
	verbose -log "$exec_output"
	return 0
    }
}

# Check to see if ld is being invoked with a non-endian output format

proc is_endian_output_format { object_flags } {

    if {[string match "*-oformat binary*" $object_flags] ||      \
        [string match "*-oformat ieee*" $object_flags] ||        \
	[string match "*-oformat ihex*" $object_flags] ||        \
	[string match "*-oformat netbsd-core*" $object_flags] || \
	[string match "*-oformat srec*" $object_flags] ||        \
	[string match "*-oformat tekhex*" $object_flags] ||      \
	[string match "*-oformat trad-core*" $object_flags] } then {
        return 0
    } else {
	return 1
    }
}

# Look for big-endian or little-endian switches in the multlib
# options and translate these into a -EB or -EL switch.  Note
# we cannot rely upon proc process_multilib_options to do this
# for us because for some targets the compiler does not support
# -EB/-EL but it does support -mbig-endian/-mlittle-endian, and
# the site.exp file will include the switch "-mbig-endian"
# (rather than "big-endian") which is not detected by proc
# process_multilib_options.

proc big_or_little_endian {} {
    
    if [board_info [target_info name] exists multilib_flags] {
	set tmp_flags " [board_info [target_info name] multilib_flags]";

	foreach x $tmp_flags {
	    case $x in {
		{*big*endian eb EB -eb -EB} {
		    set flags " -EB"
		    return $flags
		}
		{*little*endian el EL -el -EL} {
		    set flags " -EL"
		    return $flags
		}
	    }
	}
    }

    set flags ""
    return $flags
}

#
# default_ld_link 
#	link a program using ld
#
proc default_ld_link { ld target objects } {
    global HOSTING_EMU
    global HOSTING_CRT0
    global HOSTING_LIBS
    global LIBS
    global host_triplet
    global link_output
    
    set objs "$HOSTING_CRT0 $objects"
    set libs "$LIBS $HOSTING_LIBS"
    
    if { [which $ld] == 0 } then {
	perror "$ld does not exist"
	return 0
    }

    if [is_endian_output_format $objects] then {
	set flags [big_or_little_endian]
    } else {
	set flags ""
    }
    verbose -log "$ld $HOSTING_EMU $flags -o $target $objs $libs"
    
    catch "exec $ld $HOSTING_EMU $flags -o $target $objs $libs" link_output
    set exec_output [prune_warnings $link_output]
    if [string match "" $link_output] then {
	return 1
    } else {
	verbose -log "$link_output"
	return 0
    }
}

#
# default_ld_simple_link 
#	link a program using ld, without including any libraries
#
proc default_ld_simple_link { ld target objects } {
    global host_triplet
    global link_output

    if { [which $ld] == 0 } then {
	perror "$ld does not exist"
	return 0
    }
    
    if [is_endian_output_format $objects] then {
	set flags [big_or_little_endian]
    } else {
	set flags ""
    }
    
    verbose -log "$ld $flags -o $target $objects"
    
    catch "exec $ld $flags -o $target $objects" link_output
    set exec_output [prune_warnings $link_output]

    # We don't care if we get a warning about a non-existent start
    # symbol, since the default linker script might use ENTRY.
    regsub -all "(^|\n)(\[^\n\]*: warning: cannot find entry symbol\[^\n\]*\n?)" $exec_output "\\1" exec_output

    if [string match "" $exec_output] then {
	return 1
    } else {
	verbose -log "$exec_output"
	return 0
    }
}

#
# default_ld_compile 
#	compile an object using cc
#
proc default_ld_compile { cc source object } {
    global CFLAGS
    global srcdir
    global subdir
    global host_triplet
    global gcc_gas_flag

    set cc_prog $cc
    if {[llength $cc_prog] > 1} then {
	set cc_prog [lindex $cc_prog 0]
    }
    if {[which $cc_prog] == 0} then {
	perror "$cc_prog does not exist"
	return 0
    }

    catch "exec rm -f $object" exec_output

    set flags "-I$srcdir/$subdir $CFLAGS"

    # If we are compiling with gcc, we want to add gcc_gas_flag to
    # flags.  Rather than determine this in some complex way, we guess
    # based on the name of the compiler.
    if {[string match "*gcc*" $cc] || [string match "*++*" $cc]} then {
	set flags "$gcc_gas_flag $flags"
    }

    if [board_info [target_info name] exists multilib_flags] {
	append flags " [board_info [target_info name] multilib_flags]";
    }

    verbose -log "$cc $flags -c $source -o $object"

    catch "exec $cc $flags -c $source -o $object" exec_output
    set exec_output [prune_warnings $exec_output]
    if [string match "" $exec_output] then {
	if {![file exists $object]} then {
	    regexp ".*/(\[^/\]*)$" $source all dobj
	    regsub "\\.c" $dobj ".o" realobj
	    verbose "looking for $realobj"
	    if {[file exists $realobj]} then {
		verbose -log "mv $realobj $object"
		catch "exec mv $realobj $object" exec_output
		set exec_output [prune_warnings $exec_output]
		if {![string match "" $exec_output]} then {
		    verbose -log "$exec_output"
		    perror "could not move $realobj to $object"
		    return 0
		}
	    } else {
		perror "$object not found after compilation"
		return 0
	    }
	}
	return 1
    } else {
	verbose -log "$exec_output"
	perror "$source: compilation failed"
	return 0
    }
}

#
# default_ld_assemble
#	assemble a file
#
proc default_ld_assemble { as source object } {
    global ASFLAGS
    global host_triplet
    
    if {[which $as] == 0} then {
	perror "$as does not exist"
	return 0
    }

    if ![info exists ASFLAGS] { set ASFLAGS "" }

    set flags [big_or_little_endian]

    verbose -log "$as $flags $ASFLAGS -o $object $source"

    catch "exec $as $flags $ASFLAGS -o $object $source" exec_output
    set exec_output [prune_warnings $exec_output]
    if [string match "" $exec_output] then {
	return 1
    } else {
	verbose -log "$exec_output"
	perror "$source: assembly failed"
	return 0
    }
}

#
# default_ld_nm
#	run nm on a file, putting the result in the array nm_output
#
proc default_ld_nm { nm object } {
    global NMFLAGS
    global nm_output
    global host_triplet

    if {[which $nm] == 0} then {
	perror "$nm does not exist"
	return 0
    }

    if {[info exists nm_output]} {
      unset nm_output
    }

    if ![info exists NMFLAGS] { set NMFLAGS "" }

    verbose -log "$nm $NMFLAGS $object >tmpdir/nm.out"

    catch "exec $nm $NMFLAGS $object >tmpdir/nm.out" exec_output
    set exec_output [prune_warnings $exec_output]
    if [string match "" $exec_output] then {
	set file [open tmpdir/nm.out r]
	while { [gets $file line] != -1 } {
	    verbose "$line" 2
	    if [regexp "^(\[0-9a-fA-F\]+) \[a-zA-Z0-9\] (.+)$" $line whole value name] {
                set name [string trimleft $name "_"]
		verbose "Setting nm_output($name) to 0x$value" 2
		set nm_output($name) 0x$value
	    }
	}
	close $file
	return 1
    } else {
	verbose -log "$exec_output"
	perror "$object: nm failed"
	return 0
    }
}

#
# simple_diff
#	compares two files line-by-line
#	returns differences if exist
#	returns null if file(s) cannot be opened
#
proc simple_diff { file_1 file_2 } {
    global target
	
    set eof -1
    set differences 0
    
    if [file exists $file_1] then {
	set file_a [open $file_1 r]
    } else {
	warning "$file_1 doesn't exist"
	return
    }
    
    if [file exists $file_2] then {
	set file_b [open $file_2 r]
    } else {
	fail "$file_2 doesn't exist"
	return
    }
    
    verbose "# Diff'ing: $file_1 $file_2\n" 2
    
    while { [gets $file_a line] != $eof } {
	if [regexp "^#.*$" $line] then {
	    continue
	} else {
	    lappend list_a $line
	}
    }
    close $file_a
    
    while { [gets $file_b line] != $eof } {
	if [regexp "^#.*$" $line] then {
	    continue
	} else {
	    lappend list_b $line
	}
    }
    close $file_b

    for { set i 0 } { $i < [llength $list_a] } { incr i } {
	set line_a [lindex $list_a $i]
	set line_b [lindex $list_b $i]

	verbose "\t$file_1: $i: $line_a\n" 3
	verbose "\t$file_2: $i: $line_b\n" 3
	if [string compare $line_a $line_b] then {
	    verbose -log "\t$file_1: $i: $line_a\n"
	    verbose -log "\t$file_2: $i: $line_b\n"

	    fail "Test: $target"
	    return
	}
    }
    
    if { [llength $list_a] != [llength $list_b] } {
	fail "Test: $target"
	return
    }

    if $differences<1 then {
	pass "Test: $target"
    }
}

# This definition is taken from an unreleased version of DejaGnu.  Once
# that version gets released, and has been out in the world for a few
# months at least, it may be safe to delete this copy.
if ![string length [info proc prune_warnings]] {
    #
    # prune_warnings -- delete various system verbosities from TEXT
    #
    # An example is:
    # ld.so: warning: /usr/lib/libc.so.1.8.1 has older revision than expected 9
    #
    # Sites with particular verbose os's may wish to override this in site.exp.
    #
    proc prune_warnings { text } {
	# This is from sun4's.  Do it for all machines for now.
	# The "\\1" is to try to preserve a "\n" but only if necessary.
	regsub -all "(^|\n)(ld.so: warning:\[^\n\]*\n?)+" $text "\\1" text

	# It might be tempting to get carried away and delete blank lines, etc.
	# Just delete *exactly* what we're ask to, and that's it.
	return $text
    }
}