Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreeBSD port #81

Open
vrza opened this issue Jun 6, 2022 · 17 comments · May be fixed by #86
Open

FreeBSD port #81

vrza opened this issue Jun 6, 2022 · 17 comments · May be fixed by #86

Comments

@vrza
Copy link
Contributor

vrza commented Jun 6, 2022

ld (GNU binutils 2.37) segfaults when attempting to link 123 on FreeBSD:

(gdb) run
Starting program: /usr/local/bin/ld --eh-frame-hdr -dynamic-linker /libexec/ld-elf.so.1 --hash-style=both --enable-new-dtags -m elf_i386_fbsd -o bin/123 /usr/lib/crt1.o /usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib forceplt.o -lc -b coff-i386 123.o dl_init.o main.o wrappers.o patch.o filemap.o graphics.o draw.o ttydraw/ttydraw.a atfuncs/atfuncs.a forceplt.o --whole-archive ttydraw/ttydraw.a atfuncs/atfuncs.a --no-whole-archive -lncurses -lm -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed -lgcc_s --no-as-needed /usr/lib/crtend.o /usr/lib/crtn.o

Program received signal SIGSEGV, Segmentation fault.
Address not mapped to object.
strcmp () at /usr/src/lib/libc/i386/string/strcmp.S:64
64      /usr/src/lib/libc/i386/string/strcmp.S: No such file or directory.
(gdb) bt
#0  strcmp () at /usr/src/lib/libc/i386/string/strcmp.S:64
#1  0x0068271a in _bfd_generic_link_add_one_symbol ()
#2  0x006db5cd in _bfd_coff_link_add_symbols ()
#3  0x005a9a42 in load_symbols ()
#4  0x005af57f in open_input_bfds ()
#5  0x005ace97 in lang_process ()
#6  0x005b507d in main ()
(gdb) 
@taviso
Copy link
Owner

taviso commented Jun 6, 2022

You know you're doing something interesting when you crash the linker 😄

I notice you said 2.37 and not 2.38 - is it possible this is already fixed?

@vrza
Copy link
Contributor Author

vrza commented Jun 7, 2022

Now I tried building 2.38 locally (we need to modify binutils.sh to build as as well!). Linker doesn't crash anymore, but I see the same problem as on NetBSD:

$ make
./check-binutils-coff.sh
cc forceplt.o -m32 -ggdb3 -O0 -fno-stack-protector -m32 -ggdb3 -O0 -fno-stack-protector -lc -B. -Wl,-b,coff-i386 -no-pie 123.o dl_init.o main.o wrappers.o patch.o filemap.o graphics.o draw.o ttydraw/ttydraw.a atfuncs/atfuncs.a forceplt.o -Wl,--whole-archive,ttydraw/ttydraw.a,atfuncs/atfuncs.a,--no-whole-archive -o bin/123 -lncurses -lm
cc: warning: argument unused during compilation: '-no-pie' [-Wunused-command-line-argument]
./ld: 123.o:fseek.c:(.text+0xd9d8c): multiple definition of `ftell'
./ld: 123.o:getopt.c:(.text+0xda394): multiple definition of `fputs'
./ld: 123.o:mon.c:(.text+0xdb81c): multiple definition of `nlist'
./ld: 123.o: warning: warning: tempnam() possibly used unsafely; consider using mkstemp()
./ld: 123.o:time_comm.c:(.text+0xdf104): warning: warning: tmpnam() possibly used unsafely; consider using mkstemp()
./ld: 123.o:fopen.c:(.text+0xdf354): multiple definition of `mktemp'
./ld: 123.o:dtop.c:(.text+0xe183c): multiple definition of `fwrite'
./ld: 123.o:dcell.c:(.text+0xb808): multiple definition of `isnumber'
./ld: 123.o:drand48.c:(.text+0xd8e44): multiple definition of `exect'
./ld: 123.o:qsort.c:(.text+0xdc710): multiple definition of `getdents'
./ld: 123.o:ltostr.c:(.text+0xe2029): multiple definition of `brk'
./ld: forceplt.o: in function `__require_ref':
(.text+0x6f): undefined reference to `cuserid'
./ld: (.text+0x74): undefined reference to `daylight'
./ld: (.text+0x8d): undefined reference to `ecvt'
./ld: (.text+0x9c): undefined reference to `endutent'
./ld: (.text+0xce): undefined reference to `fcvt'
./ld: (.text+0xf1): undefined reference to `gcvt'
./ld: (.text+0x155): undefined reference to `getutent'
./ld: (.text+0x15a): undefined reference to `getutid'
./ld: (.text+0x15f): undefined reference to `getutline'
./ld: (.text+0x16e): undefined reference to `gsignal'
./ld: (.text+0x1c8): undefined reference to `mallinfo'
./ld: (.text+0x1d2): undefined reference to `mallopt'
./ld: (.text+0x1d7): undefined reference to `_mcount'
./ld: (.text+0x263): undefined reference to `putpwent'
./ld: (.text+0x26d): undefined reference to `pututline'
./ld: (.text+0x2db): undefined reference to `setutent'
./ld: (.text+0x32b): undefined reference to `ssignal'
./ld: (.text+0x3d0): undefined reference to `ttyslot'
./ld: (.text+0x3ee): undefined reference to `umount'
./ld: (.text+0x407): undefined reference to `utmpname'
./ld: (.text+0x461): undefined reference to `fstat64'
./ld: (.text+0x466): undefined reference to `stat64'
./ld: 123.o:lefwin.c:(.text+0x9ea88): undefined reference to `cuserid'
./ld: 123.o:baseten.c:(.text+0xc7438): undefined reference to `ecvt'
./ld: 123.o:ftw.c:(.text+0xd95ba): undefined reference to `ecvt'
./ld: 123.o:gethz.c:(.text+0xd9f11): undefined reference to `ttyslot'
./ld: 123.o:doprnt.c:(.text+0xe01d3): undefined reference to `ecvt'
./ld: 123.o:doprnt.c:(.text+0xe03d7): undefined reference to `fcvt'
./ld: 123.o:doprnt.c:(.text+0xe06bf): undefined reference to `ecvt'
./ld: forceplt.o: in function `__require_ref':
(.text+0x6f): undefined reference to `cuserid'
./ld: (.text+0x74): undefined reference to `daylight'
./ld: (.text+0x8d): undefined reference to `ecvt'
./ld: (.text+0x9c): undefined reference to `endutent'
./ld: (.text+0xce): undefined reference to `fcvt'
./ld: (.text+0xf1): undefined reference to `gcvt'
./ld: (.text+0x155): undefined reference to `getutent'
./ld: (.text+0x15a): undefined reference to `getutid'
./ld: (.text+0x15f): undefined reference to `getutline'
./ld: (.text+0x16e): undefined reference to `gsignal'
./ld: (.text+0x1c8): undefined reference to `mallinfo'
./ld: (.text+0x1d2): undefined reference to `mallopt'
./ld: (.text+0x1d7): undefined reference to `_mcount'
./ld: (.text+0x263): undefined reference to `putpwent'
./ld: (.text+0x26d): undefined reference to `pututline'
./ld: (.text+0x2db): undefined reference to `setutent'
./ld: (.text+0x32b): undefined reference to `ssignal'
./ld: (.text+0x3d0): undefined reference to `ttyslot'
./ld: (.text+0x3ee): undefined reference to `umount'
./ld: (.text+0x407): undefined reference to `utmpname'
./ld: (.text+0x461): undefined reference to `fstat64'
./ld: (.text+0x466): undefined reference to `stat64'
cc: error: linker command failed with exit code 1 (use -v to see invocation)
*** Error code 1

Stop.

Trying to figure out what's happening here -- are these undefined references symbols present on System V and Linux but not on BSD?

@vrza
Copy link
Contributor Author

vrza commented Jun 7, 2022

Okay, got it to link by modifyingundefine.lst (removed "undefined reference" symbols and added "multiple definitions" symbols -- I'm still figuring out how this custom linking process works).

Next step is fixing file mapping -- /proc/self/exe is Linux specific and thus not portable. [edit] It can be done on BSD by calling readlink on /proc/<pid>/file

@vrza
Copy link
Contributor Author

vrza commented Jun 7, 2022

Program segfaults on startup:

Program received signal SIGSEGV, Segmentation fault.
                                                    Address not mapped to object.
 0x0008e6f0 in ?? ()
(gdb) bt
#0  0x0008e6f0 in ?? ()
#1  0x0811aa27 in tc_setup_line_funcs ()
#2  0x08116d7d in tty_find_changes ()
#3  0x08116ad4 in lotus_udiv ()
#4  0x0811470c in gen_disp_txt_unlock ()
#5  0x0807eab2 in real_refresh_display ()
#6  0x0807ea52 in real_redisplay ()
#7  0x08112a5a in sched ()
#8  0x08111e4f in __unix_main ()
#9  0x0812e968 in main (argc=1, argv=0xffbfec20, envp=0xffbfec28) at main.c:151

@vrza
Copy link
Contributor Author

vrza commented Jun 7, 2022

System call trace from truss(8):

sigaction(SIGUSR1,{ 0x8113e80 SA_RESTART ss_t },{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
sigaction(SIGHUP,{ 0x811976c SA_RESTART ss_t },{ 0x8119780 SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGQUIT,{ 0x81197d8 SA_RESTART ss_t },{ 0x8119780 SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGTERM,{ 0x811976c SA_RESTART ss_t },{ 0x8119780 SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGINT,{ 0x8119854 SA_RESTART ss_t },{ 0x8119780 SA_RESTART ss_t }) = 0 (0x0)
sigaction(SIGUSR2,{ 0x8119898 SA_RESTART ss_t },{ SIG_DFL 0x0 ss_t }) = 0 (0x0)
open("/etc/localtime",O_RDONLY,05011127744)      = 4 (0x4)
fstat(4,{ mode=-r--r--r-- ,inode=19131,size=1931,blksize=4096 }) = 0 (0x0)
mmap(0x0,36864,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON|MAP_ALIGNED(12),-1,0x0) = 678113280 (0x286b3000)
read(4,"TZif2\0\0\0\0\0\0\0\0\0\0\0\0\0"...,29000) = 1931 (0x78b)
close(4)                                         = 0 (0x0)
write(1,"\^[[?25l\^[[?25l\^[[?12l\^[[?25h",24)   = 24 (0x18)
SIGNAL 11 (SIGSEGV) code=SEGV_MAPERR trapno=12 addr=0x8e6f0
write(1,"\^[[H\^[[2J\^[[?12l\^[[?25h",19)        = 19 (0x13)
ioctl(1,TIOCGETA,0xffbfe4b0)                     = 0 (0x0)
ioctl(1,TIOCGETA,0xffbfe4ac)                     = 0 (0x0)
ioctl(1,TIOCSETA,0xffbfe4ac)                     = 0 (0x0)
sigaction(SIGSEGV,{ SIG_DFL SA_RESTART ss_t },{ 0x81197d8 SA_RESTART ss_t }) = 0 (0x0)
getpid()                                         = 57116 (0xdf1c)
kill(57116,SIGSEGV)                              = 0 (0x0)
sigreturn(0xffbfe540)                            EJUSTRETURN
SIGNAL 11 (SIGSEGV) code=SI_USER pid=57116 uid=1001
process killed, signal = 11 (core dumped)

@vrza
Copy link
Contributor Author

vrza commented Jun 7, 2022

Looks like a wrapper around fwrite(3) is needed. I tried a trivial shim:

size_t __unix_fwrite(const void * __restrict ptr, size_t size, size_t nmemb, FILE * __restrict stream) {
    return fwrite(ptr, size, nmemb, stream);
}

Program runs, accepts input, the cursor moves around, but the output is all blank (no visible characters or highlighting).

@vrza
Copy link
Contributor Author

vrza commented Jun 7, 2022

My guess here is that System V struct FILE binary layout is different from the one on BSD, and that we need to convert it, but I'm not yet sure how to go about figuring out the System V FILE definition. @taviso how did you figure out the layouts of SysV stat, dirent etc?

@vrza
Copy link
Contributor Author

vrza commented Jun 7, 2022

Found SVR4 source code on archive org.

@taviso
Copy link
Owner

taviso commented Jun 7, 2022

I think maybe fwrite() should be localized, that way it can do whatever it wants to the FILE structure, but eventually when it needs to use write() that can be intercepted... I think maybe it's a bug that it's not localized already, can you check if that helps?

@taviso
Copy link
Owner

taviso commented Jun 7, 2022

(I did the same thing as you to figure out the structure, looked at the disassembly and googled for old header files!)

@vrza
Copy link
Contributor Author

vrza commented Jun 8, 2022

@taviso Spot on, intercepting write instead of fwrite worked like a charm, thank you!

FreeBSD port now seems to work 🎉

Since the undefine/redefine lists might differ between platforms, we'll need some sort of platform-specific configuration prior to build. I can try to cobble up some shell script for this. Please let me know your thoughts.

@vrza vrza linked a pull request Jun 8, 2022 that will close this issue
taviso added a commit that referenced this issue Jun 10, 2022
@Unixware
Copy link

@vrza I am curious what ver. of FreeBSD are you as not even the binutils can be compiled...

@vrza
Copy link
Contributor Author

vrza commented Jul 21, 2024

@Unixware You probably misunderstood the conversation above, the GNU binutils suite itself could be compiled on FreeBSD. Since the conversation above is from June 2022, it was probably on FreeBSD 13.1, it had devel/binutils-2.37 in ports, and I compiled a newer version (binutils-2.38) from the upstream tarball.

What's described in the conversation above are various issues in getting not binutils, but this project (123elf) to compile and link on FreeBSD (which is basically the point of this GitHub ticket) and these issues I solved back then in PR #86.

The feature branch is still up, try it on FreeBSD. By this time I'd expect it to link just fine using the ports version of binutils.

@Unixware
Copy link

Unixware commented Jul 22, 2024

thanks! Sorry I thought your PR was merged already!
I think you may need to fix the make file to reflect the correct names of i386 binutils , as they have the prefix "i386-unknown-freebsd14.0-"
edit: I think you are using a i386 FreeBSD system, as the makefile stops because the cc does not support coff-i386

@vrza
Copy link
Contributor Author

vrza commented Jul 22, 2024

@Unixware The original 123 object code that this project is linking is i386, so you must have coff-i386 in order to build it.

@Unixware
Copy link

thanks Vladimir, using the latest binutils works! 123 loads ok , Just segfault while trying to open the 'help' (F1 key)

@emaste
Copy link

emaste commented Jul 23, 2024

Next step is fixing file mapping -- /proc/self/exe is Linux specific and thus not portable. [edit] It can be done on BSD by calling readlink on /proc/<pid>/file

FreeBSD has a procfs implementation but it is not preferred, and on many systems is not normally mounted. The canonical way to query this on FreeBSD is via the sysctl(3) interface. There's a good blog on implementing this functionality for FreeBSD in GHC at https://frasertweedale.github.io/blog-fp/posts/2021-01-01-fixing-getExecutablePath-FreeBSD.html (and the sysctl node itself is documented in the man page, https://man.freebsd.org/cgi/man.cgi?sysctl(3) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants