Subject: bin/4601: crunchide fails on mips
To: None <>
From: Jonathan Stone <jonathan@DSG.Stanford.EDU>
List: netbsd-bugs
Date: 11/28/1997 20:35:39
>Number:         4601
>Category:       bin
>Synopsis:       crunchide fails on mips
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    bin-bug-people (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Nov 28 20:50:01 1997
>Originator:     Jonathan Stone
>Release:        NetBSD-1.3_ALPHA supped on 1997-11-27
System: NetBSD Reno.DSG.Stanford.EDU 1.3_ALPHA NetBSD 1.3_ALPHA (GENERIC) #0: Sat Nov 22 16:32:51 PST 1997 jonathan@Reno.DSG.Stanford.EDU:/reno/compile/GENERIC pmax


Crunchide doesn't work on mips ELF.

The mechanism it uses to hide symbols on ELF systems is to copy the
symbol table, smashing the type of `global'  symbols in the hide list
and moving them,if necessary.

This doesn't work on a mips.  Mips CPUs have limited addressing modes;
calls within a 16-bit offset range can be made via an immediate
offset.  The mips ELF abi includes special reloc types for these calls
(CALL16).  The MIPS ELF ABI seems to require that such calls be made
via the GOT and to be global.    

crunchide goes through the symbol table and happily changes the symbol
type of to-be-hidden CALL16 symbols to be static. The MIPS ABI (or at
least the GNU ld implementation of it) requires CALL16 symbols
relocated via the GOT to be global.

All the entrypoints of the uncrunched programs end up as reloc type
`CALL16' in the .lo files.  Thus, linking to the `hidden' entrypoint


	setenv DESTDIR <source build directory>
	cd /usr/src/distrib/miniroot
	make all

a log produces

	[... recheck of linkinglo libraries... ]

	crunchide -k _crunched_less_stub less.lo
	cc -static -o instbin instbin.o less.lo strings.lo cut.lo gzip.lo chroot.lo chflags.lo stty.lo gawk.lo mknod.lo init_s.lo vi.lo ping.lo rm.lo ls.lo tset.lo disklabel.lo shutdown.lo newfs.lo cp.lo tip.lo slattach.lo mount_ffs.lo mount_cd9660.lo sleep.lo mt.lo kill.lo getopt.lo mount_nfs.lo dd.lo mv.lo ed.lo cat.lo sysctl.lo installboot.lo netstat.lo sort.lo df.lo grep.lo cksum.lo expr.lo rsh.lo dmesg.lo sed.lo chmod.lo basename.lo ftp.lo route.lo ifconfig.lo fsck_ffs.lo sync.lo ln.lo tar.lo chown.lo mount.lo sh.lo mkdir.lo hostname.lo update.lo umount.lo reboot.lo test.lo pwd.lo -L/reno/build//usr/lib  -lrmt -ledit -lutil -lcurses -ltermcap -lcrypt -ll -lm -lkvm
	ld: Warning: type of symbol `_crunched_less_stub' changed from 1 to 2 in less.lo
	ld: less.lo: CALL16 reloc at 0x1c not against global symbol
	less.lo: could not read symbols: Bad value

and then ld aborts.  Examining the reloc table with
		objdump --reloc obj/less.lo

shows that offest 0x1c is the old `main' entrypoint for less.
Uh, oh.


I don't know.  The mechanism for hiding symbol names on mips elf
targets clearly needs rethinking. I don't know if it's possible to use
some other ELF symbol type for the `global' entrypoints. 

One idea is to just change the symbol names (e.g, to "_crunched_less_main"),
leave them global, and change the crunch stubs accordingly.

Another idea is to do more work link the .lo files to avoid this
problem altogether.  Shared-object libraries ( .so files) manage to
have static objects without any problems; perhaps there's some way to
link the .lo files twice, once to bind the stub to the normal `main',
then dropping the GOT-relative external reloc for `main' altogether,
and then linking (or running crunchide) a second time?

Or maybe there's a simple fix that can be applied to drop the
GOT-relative entries at the same time they're made hidden?  I don't
know enough about MIPS ELF to say for sure.

I also don't know whether it's best to do the same thing on all elf
targets (or even all elf32 targets), or if this is a mips-specific thing.
I'm guessing it could be a problem for other RISC CPUs if/when they
switch to using ELF, so I'd like to get a really clean solution..