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

Running executables from a Debian chroot #68

Open
icecream95 opened this issue Nov 4, 2019 · 36 comments
Open

Running executables from a Debian chroot #68

icecream95 opened this issue Nov 4, 2019 · 36 comments

Comments

@icecream95
Copy link
Contributor

I've tried running some executables from a first-stage bootstrapped i386 Debian chroot created using this script.

However, most programs give errors like these:

$ BOX86_LD_LIBRARY_PATH=usr/lib/i386-linux-gnu /tmp/box86/build/box86 bin/echo
BOX86_LD_LIBRARY_PATH: usr/lib/i386-linux-gnu/
Using default BOX86_PATH: ./:bin/
Counted 67 Env var
Looking for bin/echo
Using native(wrapped) libc.so.6
Using native(wrapped) ld-linux.so.2
Using native(wrapped) libpthread.so.0
Using native(wrapped) librt.so.1
Error: Symbol error not found, cannot apply R_386_JMP_SLOT @0xb6efe054 (0x1156)
Error: Symbol __overflow not found, cannot apply R_386_JMP_SLOT @0xb6f10094 (0x1256)
[1]    31884 segmentation fault (core dumped)

I tried commenting out libc from library_list.h, but then I get these errors:

$ BOX86_LD_LIBRARY_PATH=usr/lib/i386-linux-gnu /tmp/box86/build/box86 bin/echo
BOX86_LD_LIBRARY_PATH: usr/lib/i386-linux-gnu/
Using default BOX86_PATH: ./:bin/
Counted 67 Env var
Looking for bin/echo
Using emulated usr/lib/i386-linux-gnu/libc.so.6
Using native(wrapped) ld-linux.so.2
Warning, don't know of to handle rel #1306 type: R_386_TLS_TPOFF (0xb6bcfe5c)
Warning, don't know of to handle rel #1307 type: R_386_TLS_TPOFF (0xb6bcfe60)
Warning, don't know of to handle rel #1308 type: R_386_TLS_TPOFF (0xb6bcfe64)
Warning, don't know of to handle rel #1309 type: R_386_TLS_TPOFF (0xb6bcfe68)
Warning, don't know of to handle rel #1310 type: R_386_TLS_TPOFF (0xb6bcfe6c)
Warning, don't know of to handle rel #1311 type: R_386_TLS_TPOFF (0xb6bcfe70)
Warning, don't know of to handle rel #1312 type: R_386_TLS_TPOFF (0xb6bcfe74)
Warning, don't know of to handle rel #1313 type: R_386_TLS_TPOFF (0xb6bcfe78)
Warning, don't know of to handle rel #1314 type: R_386_TLS_TPOFF (0xb6bcfe7c)
Warning, don't know of to handle rel #1315 type: R_386_TLS_TPOFF (0xb6bcfe80)
Warning, don't know of to handle rel #1316 type: R_386_TLS_TPOFF (0xb6bcfe94)
Warning, don't know of to handle rel #1317 type: R_386_TLS_TPOFF (0xb6bcfebc)
Warning, don't know of to handle rel #1318 type: R_386_TLS_TPOFF (0xb6bcfeec)
Warning, don't know of to handle rel #1319 type: R_386_TLS_TPOFF (0xb6bcfef4)
Warning, don't know of to handle rel #1320 type: R_386_TLS_TPOFF (0xb6bcff40)
Warning, don't know of to handle rel #1321 type: R_386_TLS_TPOFF (0xb6bcff70)
Warning, don't know of to handle rel #1322 type: R_386_TLS_TPOFF (0xb6bcffe4)
Error: Global Symbol __libpthread_freeres not found, cannot apply R_386_GLOB_DAT @0xb6bcfe9c ((nil))
Error: Global Symbol _dl_starting_up not found, cannot apply R_386_GLOB_DAT @0xb6bcff84 ((nil))
Error: Global Symbol __libdl_freeres not found, cannot apply R_386_GLOB_DAT @0xb6bcffa4 ((nil))
Error: Global Symbol _dl_argv not found, cannot apply R_386_GLOB_DAT @0xb6bcffe0 ((nil))
Error: Symbol _dl_exception_create not found, cannot apply R_386_JMP_SLOT @0xb6bd001c (0x19056)
Error: Symbol __tunable_get_val not found, cannot apply R_386_JMP_SLOT @0xb6bd0024 (0x19076)
Error: Symbol _dl_find_dso_for_object not found, cannot apply R_386_JMP_SLOT @0xb6bd002c (0x19096)
Warning, don't know of to handle rel #8 type: 0x2a (unknown) (0xb6bd0028)
Warning, don't know of to handle rel #9 type: 0x2a (unknown) (0xb6bd0020)
Warning, don't know of to handle rel #10 type: 0x2a (unknown) (0xb6bd0014)
Error: Global Symbol _ITM_deregisterTMCloneTable not found, cannot apply R_386_GLOB_DAT @0xb6f7bfbc ((nil))
Error: Global Symbol __gmon_start__ not found, cannot apply R_386_GLOB_DAT @0xb6f7bfcc ((nil))
Error: Global Symbol _ITM_registerTMCloneTable not found, cannot apply R_386_GLOB_DAT @0xb6f7bfe4 ((nil))
Error: Symbol strcmp not found, cannot apply R_386_JMP_SLOT @0xb6f7c00c (0x1036)
Error: Symbol memcpy not found, cannot apply R_386_JMP_SLOT @0xb6f7c01c (0x1076)
Error: Symbol memcmp not found, cannot apply R_386_JMP_SLOT @0xb6f7c02c (0x10b6)
Error: Symbol strlen not found, cannot apply R_386_JMP_SLOT @0xb6f7c070 (0x11c6)
Error: Symbol memset not found, cannot apply R_386_JMP_SLOT @0xb6f7c078 (0x11e6)
Error: Symbol strrchr not found, cannot apply R_386_JMP_SLOT @0xb6f7c090 (0x1246)
Error: Symbol strncmp not found, cannot apply R_386_JMP_SLOT @0xb6f7c0a4 (0x1296)
[1]    32701 segmentation fault (core dumped)

(With a wrapped libc.so, many programs can display their help text, and quite a few, such as cat, sort, gzip, dd, env, sleep and dmesg do work.)

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

I probably need to add "error" and "__overflow" wrapped function to Box86 (error is a bit tricky, but __overflow is a trivial "iFpi" function).
Are you using the main branch or the dynarec one (it shouldn't change much the result of your current tests anyway)?

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

FYI, I have added the 2 missing function in the Dynarec branch.

@icecream95
Copy link
Contributor Author

Thanks.

du doesn't work:

16806|0xb6fbeea7: Calling malloc (00000014, 00000000, B6FBE2B0...) => return 0xA810FBD8

Program received signal SIGSEGV, Segmentation fault.
0xb6dcbaee in strlen () from /usr/lib/libc.so.6
(gdb) bt
#0  0xb6dcbaee in strlen () from /usr/lib/libc.so.6
#1  0xb6da8b00 in __vfprintf_internal () from /usr/lib/libc.so.6
#2  0xb6dba72c in __vsnprintf_internal () from /usr/lib/libc.so.6
#3  0xb6d98464 in snprintf () from /usr/lib/libc.so.6
#4  0xa807a5f0 in x86Int3 (emu=0xa80f7d70) at /tmp/box86/src/emu/x86int3.c:95
#5  0xa804e2d8 in Run (emu=0xa80f7d70, step=-104, step@entry=0) at /tmp/box86/src/emu/x86run.c:839
#6  0xa80287d0 in main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>) at /tmp/box86/src/main.c:533
(gdb) up 4
#4  0xa807a5f0 in x86Int3 (emu=0xa80f7d70) at /tmp/box86/src/emu/x86int3.c:95
95                          snprintf(buff, 255, "%04d|%p: Calling %s(\"%s\", %d)", tid, *(void**)(R_ESP), s, *(char**)(R_ESP+4), *(int*)(R_ESP+8));
(gdb) p s
$5 = 0xb6ffe8c8 <__stack_chk_guard> ""

glxgears runs at native speed (with vblank_mode=0 to disable vsync).
I added some libpng symbols, and glmark2 runs, at 90% of native performance:

BOX86_LD_LIBRARY_PATH: /tmp/mu/lib/i386-linux-gnu/:/tmp/mu/usr/lib/i386-linux-gnu/
Using default BOX86_PATH: ./:bin/
Counted 67 Env var
Looking for ./glmark2
Using native(wrapped) libjpeg.so.8
Using native(wrapped) libpng16.so.16
Using native(wrapped) libX11.so.6
Using native(wrapped) libGL.so.1
Using emulated /tmp/mu/usr/lib/i386-linux-gnu/libstdc++.so.6
Using native(wrapped) libm.so.6
Using native(wrapped) libc.so.6
Using native(wrapped) ld-linux.so.2
Using native(wrapped) libpthread.so.0
Using native(wrapped) librt.so.1
Using emulated /tmp/mu/lib/i386-linux-gnu/libgcc_s.so.1
Warning: Weak Symbol _ZGTtnaj not found, cannot apply R_386_JMP_SLOT @0xb66af198 (0x6b666)
Warning: Weak Symbol _ZGTtdlPv not found, cannot apply R_386_JMP_SLOT @0xb66af474 (0x6c1d6)
=======================================================
    glmark2 2014.03+git20150611.fa71af2d
=======================================================
    OpenGL Information
    GL_VENDOR:     panfrost
    GL_RENDERER:   panfrost
    GL_VERSION:    2.1 Mesa 19.3.0-devel (git-075a96aa92)
=======================================================
[build] use-vbo=false: FPS: 532 FrameTime: 1.880 ms
[build] use-vbo=true: FPS: 851 FrameTime: 1.175 ms
[texture] texture-filter=nearest: FPS: 868 FrameTime: 1.152 ms
[texture] texture-filter=linear: FPS: 858 FrameTime: 1.166 ms
[texture] texture-filter=mipmap: FPS: 956 FrameTime: 1.046 ms
[shading] shading=gouraud: FPS: 584 FrameTime: 1.712 ms
[shading] shading=blinn-phong-inf: FPS: 588 FrameTime: 1.701 ms
[shading] shading=phong: FPS: 498 FrameTime: 2.008 ms
[shading] shading=cel: FPS: 460 FrameTime: 2.174 ms
[bump] bump-render=high-poly: FPS: 260 FrameTime: 3.846 ms
[bump] bump-render=normals: FPS: 1094 FrameTime: 0.914 ms
[bump] bump-render=height: FPS: 936 FrameTime: 1.068 ms
[effect2d] kernel=0,1,0;1,-4,1;0,1,0;: FPS: 704 FrameTime: 1.420 ms
[effect2d] kernel=1,1,1,1,1;1,1,1,1,1;1,1,1,1,1;: FPS: 190 FrameTime: 5.263 ms
[pulsar] light=false:quads=5:texture=false: FPS: 1045 FrameTime: 0.957 ms
[desktop] blur-radius=5:effect=blur:passes=1:separable=true:windows=4: FPS: 113 FrameTime: 8.850 ms
[desktop] effect=shadow:windows=4: FPS: 409 FrameTime: 2.445 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 13 FrameTime: 76.923 ms
[buffer] columns=200:interleave=false:update-dispersion=0.9:update-fraction=0.5:update-method=subdata: FPS: 13 FrameTime: 76.923 ms
[buffer] columns=200:interleave=true:update-dispersion=0.9:update-fraction=0.5:update-method=map: FPS: 18 FrameTime: 55.556 ms
[ideas] speed=duration: FPS: 154 FrameTime: 6.494 ms
[jellyfish] <default>: FPS: 371 FrameTime: 2.695 ms
=======================================================
                                  glmark2 Score: 523
=======================================================

The terrain bench crashes with SIGILL in jpeg_CreateDecompress:

#0  0xb6c71f60 in ?? ()
#1  0xb6b16f88 in jpeg_CreateDecompress () from /usr/lib/libjpeg.so.8
#2  0xa8079c94 in x86Int3 (emu=0xa80f7d98) at /tmp/box86/src/emu/x86int3.c:204
#3  0xa804e2d8 in Run (emu=0xa80f7d98, step=80, step@entry=0) at /tmp/box86/src/emu/x86run.c:839
#4  0xa80287d0 in main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>) at /tmp/box86/src/main.c:533

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

The du issue: not sure what is happening. The crash you backtrace is box86 own trace that try to printf some NULL string. That's bad but this crash shouldn't happens if you run without any log right?

About glmark2: 90% of native is very good :D \o/. I guess you are using the dynarec to get that number.

The jpeg crash, well, that probably a callback that I didn't wrapped. I'll check that back later.

@icecream95
Copy link
Contributor Author

When running du without logging, I just get:

Counted 69 Env var
Looking for du
Using native(wrapped) libc.so.6
Using native(wrapped) ld-linux.so.2
Using native(wrapped) libpthread.so.0
Using native(wrapped) librt.so.1
./du: cannot read directory '..': Invalid argument
0       ..

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

Ah, sounds like a bug in an dynarec opcode.
Can you try without dynarec (using BOX86_DYNAREC=0)

@icecream95
Copy link
Contributor Author

I actually wasn't using dynarec - I didn't realise you had to run cmake with -DARM_DYNAREC=1...

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

Ah, damn, so that's a bug even in the Interpretor (so glmark2 runing at 90% with the interpretor, glmark is mostly GL code, with very few C code around the tests)

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

Also, I should have fixed the crash in du when using BOX86_LOG=3

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

And I have just pused some changes in COMPILE.md about Dynarec compilation.

Be sure to have -m32 in you compilation flags, or the Dynarec will probably not work (and just segfault).
I'll make that parameter automatic in cmake project later.

@icecream95
Copy link
Contributor Author

icecream95 commented Nov 4, 2019

For du, the function that is trying to be logged is openat64. The strstr(s, "open") matches that, so it logs the function wrong. I think du doesn't work properly without logging because I didn't add one of the symbols it needs properly.

I recompiled with dynarec, and gzip went from 3.5% of native speed to 25% of native, which is a big improvement. glmark2 now runs at 98% of native speed.

When running make in parallel, it doesn't wait for wrapper.h to be built before building files that depend on it, so I have to use make clean; timeout 1 make; make -j8 to compile box86 properly.

EDIT: I recompiled without my patches and du behaves in the same way.

@icecream95
Copy link
Contributor Author

icecream95 commented Nov 4, 2019

strace shows that this call is causing the error:

openat(AT_FDCWD, ".", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)

With native du:

openat(AT_FDCWD, ".", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE|O_NOFOLLOW|O_CLOEXEC|O_DIRECTORY) = 3

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

Ah, nice intel. So the O_DIRECTORY is missing.

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 4, 2019

and O_DIRECT should not be there. And O_NOFOLLOW is also missing

@icecream95
Copy link
Contributor Author

The only important one is O_DIRECT, which newer kernels don't like:

https://bugzilla.redhat.com/show_bug.cgi?id=567113#c11

@icecream95
Copy link
Contributor Author

This also happens with grep -r:

openat(AT_FDCWD, ".", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_DIRECT|O_LARGEFILE|O_CLOEXEC) = -1 EINVAL (Invalid argument)

@icecream95
Copy link
Contributor Author

It seems the flags are different between architectures so some translation will have to be done.

@icecream95
Copy link
Contributor Author

These are the differences:

Flag Arm x86
O_DIRECTORY 040000 0200000
O_DIRECT 0200000 040000
O_NOFOLLOW 0100000 0400000
O_LARGEFILE 0400000 0100000

So the O_DIRECTORY flag on x86 is the O_DIRECT flag on arm.

This could be fixed with something like (untested):

flag = (flag&~0740000) + (flag&0140000)*4 + (flag&0600000)/4;

for all the functions using these flags, maybe by adding an "I/O flag type" for the wrapper functions.

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 5, 2019

Wow, nice debug. Thanks a lot!
So the bad news is , I need to wrap many functions because of that.

@icecream95
Copy link
Contributor Author

I think only the open.* functions need fixing, everything else should be fine.

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 5, 2019

So, I tried to a push a first workarournd with commit aad4c91

I'll try to get a more portable solution later.

@icecream95
Copy link
Contributor Author

So, did you just grep for functions taking flags? Most of these flag types are unrelated.

Also, they aren't AT_ flags, they're file open flags - maybe you got mixed up with the first field of openat, which can be an AT_ flag.

du does at least somewhat work, but does crash with abort (core dumped) partway though.

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 5, 2019

bah yeah, I somewhat looked for "at" function using flags. I'll recheck what flags it is, maybe I was a bit too fast :(

@icecream95
Copy link
Contributor Author

diff --git a/rebuild_wrappers.py b/rebuild_wrappers.py
index c037a83..042956d 100755
--- a/rebuild_wrappers.py
+++ b/rebuild_wrappers.py
@@ -4,7 +4,7 @@ import os
 import glob
 import sys
 
-values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'L', 'p', 'V']
+values = ['E', 'e', 'v', 'c', 'w', 'i', 'I', 'C', 'W', 'u', 'U', 'f', 'd', 'D', 'L', 'p', 'V', 'O']
 def splitchar(s):
 	ret = [len(s)]
 	i = 0
@@ -226,6 +226,11 @@ typedef union ui64_s {
 #else
 #define ST0val ST0.d
 #endif
+#ifndef NOALIGN
+int oflag_convert(int flag) { return (flag&~0740000) + (flag&0140000)*4 + (flag&0600000)/4; }
+#else
+int oflag_convert(int flag) { return flag; }
+#endif
 
 """,
 		"wrapper.h": """/*****************************************************************
@@ -249,6 +254,7 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
 // o = stdout
 // C = unsigned byte c = char
 // W = unsigned short w = short
+// O = file open flag
 // Q = ...
 // S8 = struct, 8 bytes
 
@@ -292,8 +298,8 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
 		
 		# First part: typedefs
 		for v in gbl["()"]:
-			#         E            e             v       c         w          i          I          C          W           u           U           f        d         D              L         p        V
-			types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "void*", "void*"]
+			#         E            e             v       c         w          i          I          C          W           u           U           f        d         D              L         p        V        O
+			types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "void*", "void*", "int32_t"]
 			if len(values) != len(types):
 					raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
 			
@@ -303,8 +309,8 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
 			if k != "()":
 				file.write("\n#if " + k + "\n")
 				for v in gbl[k]:
-					#         E            e             v       c         w          i          I          C          W           u           U           f        d         D              L         p        V
-					types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "void*", "void*"]
+					#         E            e             v       c         w          i          I          C          W           u           U           f        d         D              L         p        V        O
+					types = ["x86emu_t*", "x86emu_t**", "void", "int8_t", "int16_t", "int32_t", "int64_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t", "float", "double", "long double", "double", "void*", "void*", "int32_t"]
 					if len(values) != len(types):
 							raise NotImplementedError("len(values) = {lenval} != len(types) = {lentypes}".format(lenval=len(values), lentypes=len(types)))
 					
@@ -344,10 +350,11 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
 				"*(long double*)(R_ESP + {p}), ", # D
 				"FromLD((void*)(R_ESP + {p})), ", # L
 				"*(void**)(R_ESP + {p}), ",       # p
-				"(void*)(R_ESP + {p}), "          # V
+				"(void*)(R_ESP + {p}), ",         # V
+                                "oflag_convert(*(int32_t*)(R_ESP + {p})), ", # O
 			]
-			#         E  e  v  c  w  i  I  C  W  u  U  f  d  D   L   p  V  
-			deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 0]
+			#         E  e  v  c  w  i  I  C  W  u  U  f  d  D   L   p  V  O
+			deltas = [0, 0, 4, 4, 4, 4, 8, 4, 4, 4, 8, 4, 8, 12, 12, 4, 0, 4]
 			if len(values) != len(arg):
 				raise NotImplementedError("len(values) = {lenval} != len(arg) = {lenarg}".format(lenval=len(values), lenarg=len(arg)))
 			if len(values) != len(deltas):
@@ -374,6 +381,7 @@ typedef void (*wrapper_t)(x86emu_t* emu, uintptr_t fnc);
 				"double db=fn({0}); fpu_do_push(emu); ST0val = db;",            # L
 				"R_EAX=(uintptr_t)fn({0});",                                    # p
 				"\n#error Invalid return type: va_list\n",                      # V
+				"\n#error Invalid return type: oflag\n",                        # O
 			]
 			if len(values) != len(vals):
 				raise NotImplementedError("len(values) = {lenval} != len(vals) = {lenvals}".format(lenval=len(values), lenvals=len(vals)))
diff --git a/src/wrapped/wrappedlibc_private.h b/src/wrapped/wrappedlibc_private.h
index 79562ec..150eaa6 100755
--- a/src/wrapped/wrappedlibc_private.h
+++ b/src/wrapped/wrappedlibc_private.h
@@ -1188,15 +1188,15 @@ GO(_obstack_newchunk, vFpi)
 GOM(obstack_vprintf, iFEppVV)  // Weak
 // __obstack_vprintf_chk
 // on_exit  // Weak
-GOM(open, iFEpiu)    //Weak
-GOM(__open, iFEpiu) //Weak
-GO(__open_2, iFpi)
-GOM(open64, iFEpiu) //Weak
+GOM(open, iFEpOu)    //Weak
+GOM(__open, iFEpOu) //Weak
+GO(__open_2, iFpO)
+GOM(open64, iFEpOu) //Weak
 // __open64 // Weak
-GO(__open64_2, iFpi)
-GOW(openat, iFipiu)
+GO(__open64_2, iFpO)
+GOW(openat, iFipOu)
 // __openat_2
-GOW(openat64, iFipiuuuuu)   // variable arg...
+GOW(openat64, iFipOuuuuu)   // variable arg...
 // __openat64_2
 // __open_catalog
 GOW(opendir, pFp)

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 5, 2019

Ah oops, I didn't saw your post and did ... just like you :) !

@icecream95
Copy link
Contributor Author

Rather than do (flag&~0740000) & (flag&0140000)<<2 | (flag&0600000)>>2, you need to do (flag&~0740000) + (flag&0140000)*4 + (flag&0600000)/4.

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 5, 2019

I did an &? Wow, sorry for that.
I prefer to use logical operation for flags, that why I used ors and shifts. but the and is a mistake, I'll fix that, and add parenthesis around shift just to be sure.

@icecream95
Copy link
Contributor Author

My way is faster, though:

#include <iostream>
#include <chrono>
int arith(int flag) {
    return (flag&~0740000) + (flag&0140000)*4 + (flag&0600000)/4;
}
int log(int flag) {
    return (flag&~0740000) | ((flag&0140000)<<2) | ((flag&0600000)>>2);
}
int main()
{
    for (int i = 0; i < 11; ++i)
    {
        for (auto& x : {arith, log})
        {
            unsigned p = 0;
            auto start = std::chrono::steady_clock::now();
            for (int i = 0; i < 200000000; ++i)
                p += x(i);
            auto end = std::chrono::steady_clock::now();
            std::chrono::duration<double> elapsed_seconds = end-start;
            if (i)
                std::cout << p << " elapsed time: " << elapsed_seconds.count() << "s\n";
        }
    }
}
$ g++ --version
g++ (GCC) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ g++ test.cpp -o test -O3
$ ./test
3649838848 elapsed time: 0.784133s
3649838848 elapsed time: 0.871706s
3649838848 elapsed time: 0.786289s
3649838848 elapsed time: 0.874663s
3649838848 elapsed time: 0.791375s
3649838848 elapsed time: 0.869405s
3649838848 elapsed time: 0.781652s
3649838848 elapsed time: 0.872683s
3649838848 elapsed time: 0.781764s
3649838848 elapsed time: 0.869669s
3649838848 elapsed time: 0.782279s
3649838848 elapsed time: 0.871678s
3649838848 elapsed time: 0.781617s
3649838848 elapsed time: 0.870333s
3649838848 elapsed time: 0.781778s
3649838848 elapsed time: 0.873591s
3649838848 elapsed time: 0.78662s
3649838848 elapsed time: 0.869386s
3649838848 elapsed time: 0.781619s
3649838848 elapsed time: 0.870121s
Total time for arith:  7.839126s
Total time for log:    8.713235s

You can say "broken compiler" all you want, but at least for current compilers, using arithmetic operators is over 10% faster.

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 5, 2019

Oh, that's a bit surprising.
I checked with godbolt compiler explorer the asm output for both function, to understand the speed difference: https://godbolt.org/z/fm89Tv

And has you can see, the artimetic as 1 instruction more.
The difference is that this

add     r3, r3, r2, lsl #2

in the addition pus a left shift (the *4)
became

lsl     r3, r0, #2
...
orr     r3, r3, r2

So yeah, compiler optimisation issue, it could have use the same trick and do an or with the left shift.
Not a big deal, but it seems math are more optimized than logic.

Anyway, why I stick to Logic is not for speed (that not really important there), but for safety. As you have already seen, I do A LOT of mistakes... And applying 2 times the same flags (by mistake) with a OR is harmless, while with an ADD, it's not the same ending flag at all.

@icecream95
Copy link
Contributor Author

With this patch, another one to force logging to /dev/null and some more wrapped functions, I can use proot to get an emulated shell working:

diff --git a/src/main.c b/src/main.c
index 88bb131..4289d95 100755
--- a/src/main.c
+++ b/src/main.c
@@ -271,6 +272,10 @@ void PrintHelp() {
 }

 int main(int argc, const char **argv, const char **env) {
+    if(argc > 1 && !strcmp(argv[1], "-E")) {
+        argv += 4;
+        argc -= 4;
+    }

     // trying to open and load 1st arg
     if(argc==1) {
$ ls --version | head -n1
ls (GNU coreutils) 8.31
$ BOX86_LD_LIBRARY_PATH=/usr/lib/i386-linux-gnu proot -q /tmp/box86/build/box86 -R . -w / /bin/bash --norc
bash-5.0$ arch
i686
bash-5.0$ cat /proc/
Display all 209 possibilities? (y or n)
bash-5.0$ cat /proc/cpuinfo | grep -i arm
model name      : ARMv7 Processor rev 1 (v7l)
model name      : ARMv7 Processor rev 1 (v7l)
model name      : ARMv7 Processor rev 1 (v7l)
model name      : ARMv7 Processor rev 1 (v7l)
bash-5.0$ ls --version | head -n1
ls (GNU coreutils) 8.30
bash-5.0$ /host-rootfs/bin/file -m /host-rootfs/usr/share/file/misc/magic /host-rootfs/bin/file
/host-rootfs/bin/file: ELF 32-bit LSB pie executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=c69cd255292653ec64033ee6ce47daa24bbeb913, for GNU/Linux 3.2.0, stripped
bash-5.0$ /host-rootfs/bin/file -m /host-rootfs/usr/share/file/misc/magic /bin/ls
/bin/ls: ELF 32-bit LSB pie executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=728a8169184c77ded3f193547fec36a7a7186b08, stripped
bash-5.0$ which ls
Segmentation fault (core dumped)
bash-5.0$ /bin/ls /
bin  debootstrap  dev  etc  home  host-rootfs  lib  lib64  libx32  proc  run  sbin  sys  test  tmp  usr  var
bash-5.0$

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 5, 2019

For the logging, why not using the env var BOX86_LOG=0?
(also, the initial plan was to have default logging to 0, but while it's still heavily developped, I fixed it to 1, but maybe it would be a good idea to soon put the default back to 0.

Do you want your argc/argv patch to be merge? A chroot is interesting :)
I see the wich ls command segfaulted.

What function did you had to wrap?

@icecream95
Copy link
Contributor Author

proot doesn't seem to pass environment variables to box86 properly.

The argv/argc patch should probably be fixed by adding an option to proot to not prepend command-line options that would be used by qemu.

which is actually a shell script.

If I execute it manually with bash, or dash and a shell option, it works:

bash-5.0$ which ls
Segmentation fault (core dumped)
bash-5.0$ bash /bin/which ls
bin/ls
bash-5.0$ dash /bin/which ls
Segmentation fault (core dumped)
bash-5.0$ dash -e /bin/which ls
/usr/bin/ls

I've attached a patch with the extra functions I have wrapped:

wrappedlibc_private.patch

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 6, 2019

Do you mind if I push your wrappers in?

@icecream95
Copy link
Contributor Author

That's why I've posted them.

@ptitSeb
Copy link
Owner

ptitSeb commented Nov 6, 2019

Great, thanks. It's done.

@ptitSeb
Copy link
Owner

ptitSeb commented Oct 11, 2022

I think this ticket can be closed now!

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

No branches or pull requests

2 participants