台风登陆上海。昨晚在半梦半醒之间听到窗外风声大作。
今早到格蠹园一看,包括番茄架和黄瓜架等几个质量欠佳的“豆腐渣工程”如预料的那样被大风吹倒在地。台风真是检查质量的“包青天”。
早饭之后,和女儿一起学习BOX64项目。目的有两个:一是故意带一带放暑假的女儿,二是自己也想学。
女儿也很赞成这个提议,拿着笔记本到了我在家里的软件工作台。于是周末的开源学习项目便开始了。
以下是获取代码和编译构建的基本步骤:
git clone https://github.com够/ptitSeb/box64.git
cd box64
mkdir bld
cd bld
cmake ..
make
我们是使用各自的笔记本通过ssh连接到幽兰代码本。
以上过程都非常顺利,只有下载软代码可能需要重试几次。
构建成功后,执行sudo make install将构建出的box64安装到系统文件夹,方便使用。
sudo make install
[sudo] password for geduer:
[ 13%] Built target interpreter
[ 13%] Built target WRAPPERS
[100%] Built target box64
Install the project...
-- Install configuration: "RelWithDebInfo"
-- Installing: /usr/local/bin/box64
-- Installing: /etc/binfmt.d/box64.conf
-- Installing: /etc/box64.box64rc
-- Installing: /usr/lib/x86_64-linux-gnu/libstdc++.so.5
-- Installing: /usr/lib/x86_64-linux-gnu/libstdc++.so.6
-- Installing: /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
-- Installing: /usr/lib/x86_64-linux-gnu/libpng12.so.0
-- Installing: /usr/lib/x86_64-linux-gnu/libcrypto.so.1.1
-- Installing: /usr/lib/x86_64-linux-gnu/libcrypto.so.1.0.0
-- Installing: /usr/lib/x86_64-linux-gnu/libssl.so.1.1
-- Installing: /usr/lib/x86_64-linux-gnu/libssl.so.1.0.0
-- Installing: /usr/lib/x86_64-linux-gnu/libunwind.so.8
-- Installing: /usr/lib/x86_64-linux-gnu/libmbedx509.so.1
-- Up-to-date: /usr/lib/x86_64-linux-gnu/libmbedx509.so.0
-- Installing: /usr/lib/x86_64-linux-gnu/libmbedtls.so.14
-- Up-to-date: /usr/lib/x86_64-linux-gnu/libmbedtls.so.12
-- Installing: /usr/lib/x86_64-linux-gnu/libmbedcrypto.so.7
-- Up-to-date: /usr/lib/x86_64-linux-gnu/libmbedcrypto.so.3
体验效果
然后我选择我喜欢的gematrix程序做实验。刚好幽兰的gelabs下有这个程序的x64版本。在arm64的幽兰上运行会报告执行格式错误。
geduer@ulan:~/gelabs/gematrix$ ./gematrix
-bash: ./gematrix: cannot execute binary file: Exec format error
使用readelf -h观察,可以看到它是AMD64格式的。
geduer@ulan:~/gelabs/gematrix$ readelf -h gematrix
ELF Header:
Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
Class: ELF64
Data: 2's complement, little endian
Version: 1 (current)
OS/ABI: UNIX - System V
ABI Version: 0
Type: EXEC (Executable file)
Machine: Advanced Micro Devices X86-64
Version: 0x1
Entry point address: 0x400f60
Start of program headers: 64 (bytes into file)
Start of section headers: 16888 (bytes into file)
Flags: 0x0
Size of this header: 64 (bytes)
Size of program headers: 56 (bytes)
Number of program headers: 9
Size of section headers: 64 (bytes)
Number of section headers: 31
Section header string table index: 28
如何让box64发挥作用呢?只要在命令行前加上box64前缀就可以了。box64 ./gematrix
geduer@ulan:~/gelabs/gematrix$ box64 ./gematrix
PageSize:4096 Running on Cortex-A55 Cortex-A76 with 8 Cores
Will use time-based emulation for rdtsc, even if hardware counter are available
Will use Software counter measured at 1.0 GHz emulating 2.0 GHz
Params database has 87 entries
Box64 v0.3.1 a8784eff built on Jul 27 2024 10:25:43
BOX64: Didn't detect 48bits of address space, considering it's 39bits
Counted 26 Env var
BOX64 LIB PATH: ./:lib/:lib64/:x86_64/:bin64/:libs64/:/lib/x86_64-linux-gnu/:/usr/lib/x86_64-linux-gnu/:/usr/x86_64-linux-gnu/lib/
BOX64 BIN PATH: ./:bin/:/usr/local/sbin/:/usr/local/bin/:/usr/sbin/:/usr/bin/:/sbin/:/bin/:/usr/games/:/usr/local/games/:/snap/bin/
Looking for ./gematrix
Rename process to "gematrix"
Using native(wrapped) libpthread.so.0
Using native(wrapped) libc.so.6
Using native(wrapped) ld-linux-x86-64.so.2
Using native(wrapped) libdl.so.2
Using native(wrapped) libutil.so.1
Using native(wrapped) librt.so.1
Using native(wrapped) libbsd.so.0
Matrix sample rev1.2 for tunning experiments. Improved by Raymond, based on the sample from VTune
Usage: matrix [thread_num] [algorithm no]
Collected thread no -1, algorithm no 1
Addr of buf1 = 0x7fa869f010
Offs of buf1 = 0x7fa869f180
Addr of buf2 = 0x7fa669e010
Offs of buf2 = 0x7fa669e1c0
Addr of buf3 = 0x7fa469d010
Offs of buf3 = 0x7fa469d100
Addr of buf4 = 0x7fa269c010
Offs of buf4 = 0x7fa269c140
Threads #: 8 Pthreads
Matrix size: 2048
Using multiply kernel: multiply1
开头的一些信息是box64输出的,包括box64的版本号和构建日期:
Box64 v0.3.1 a8784eff built on Jul 27 2024 10:25:43
还有关于地址空间的。
BOX64: Didn't detect 48bits of address space, considering it's 39bits
这条信息意味深长,值得细细品味。对于64位的Linux,x64 CPU使用的是48位线性地址,而ARM64一般使用的是39位线性地址。48位线性地址意味着四级页表结构,而39位线性地址意味着3级页表结构,地址翻译时可以少查一次页表。我在庐山研习班上多次仔细讲过这个细节。
从下面这句开始就是gematrix程序的输出了。
Matrix sample rev1.2 for tunning experiments. Improved by Raymond, based on the sample from VTune
上gdb
为了理解box64的工作原理,我们继续做试验。在命令行前面增加gdb --args让上面的过程在gdb的监视下运行。
gdb --args box64 ./gematrix
geduer@ulan:~/gelabs/gematrix$ gdb --args box64 ./gematrix
GNU gdb (Ubuntu 14.0.50.20230907-0ubuntu1) 14.0.50.20230907-git
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "aarch64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from box64...
(gdb)
gdb成功读取符号,这是自己构建box64带来的便利。
Reading symbols from box64...
(gdb) b main
Breakpoint 1 at 0x349f0480: file /home/Ada/box64/src/main.c, line 3.
使用b main设置一个断点后,发出r命令运行到box64的主函数。
(gdb) r
Starting program: /usr/local/bin/box64 ./gematrix
This GDB supports auto-downloading debuginfo from the following URLs:
<https://debuginfod.ubuntu.com>
Enable debuginfod for this session? (y or [n]) y
Debuginfod has been enabled.
To make this setting permanent, add 'set debuginfod enabled on' to .gdbinit.
Downloading separate debug info for system-supplied DSO at 0x7ff7ffb000
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/aarch64-linux-gnu/libthread_db.so.1".
Breakpoint 1, main (argc=2, argv=0x7ffffff348, env=0x7ffffff360) at /home/Ada/box64/src/main.c:3
3 int main(int argc, const char **argv, char **env) {
(gdb) l
1 #include "core.h"
2
3 int main(int argc, const char **argv, char **env) {
4
5 x64emu_t* emu = NULL;
6 elfheader_t* elf_header = NULL;
7 if (initialize(argc, argv, env, &emu, &elf_header, 1)) {
8 return -1;
9 }
10
11 return emulate(emu, elf_header);
12 }
在今天这样的软件时代,代码是全世界最通用的语言。看box64的main函数,函数体非常短,可谓简洁之至。
但值得注意的是,main函数的参数很“长”。说很长是说它有三个参数。main函数的原型一般有两种:
int main() { body } (1)
int main(int argc, char* argv[]) { body } (2)
而这里使用了比较少见的三个参数。根据C99和C++扩展,main函数可以使用“实现者定义的”第三种形式。
int main(/* implementation-defined */) { body } (3)
这里的实现者应该是指编译器和操作系统的实现者,查阅gcc的文档可看到,box64使用的是gcc支持的第三种形式:
int main (void) {…}
int main (int argc, char *argv[]) {…}
int main (int argc, char *argv[], char *envp[]) {…}
使用gdb观察envp,可以看到里面是很多个环境变量对。
(gdb) p env[0]@28
$4 = {0x7ffffff5c2 "SHELL=/bin/bash", 0x7ffffff5d2 "PWD=/home/geduer/gelabs/gematrix", 0x7ffffff5f3 "LOGNAME=geduer",
0x7ffffff602 "XDG_SESSION_TYPE=tty", 0x7ffffff617 "_=/usr/bin/gdb", 0x7ffffff626 "LINES=33",
0x7ffffff62f "HOME=/home/geduer",
0x7ffffff641 "LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=00:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01"...,
0x7ffffffd25 "COLUMNS=119", 0x7ffffffd31 "SSH_CONNECTION=192.168.0.104 63711 192.168.0.103 22",
0x7ffffffd65 "LESSCLOSE=/usr/bin/lesspipe %s %s", 0x7ffffffd87 "XDG_SESSION_CLASS=user", 0x7ffffffd9e "TERM=xterm",
0x7ffffffda9 "LESSOPEN=| /usr/bin/lesspipe %s", 0x7ffffffdc9 "USER=geduer", 0x7ffffffdd5 "DISPLAY=localhost:12.0",
0x7ffffffdec "SHLVL=1", 0x7ffffffdf4 "XDG_SESSION_ID=35", 0x7ffffffe06 "XDG_RUNTIME_DIR=/run/user/1000",
0x7ffffffe25 "SSH_CLIENT=192.168.0.104 63711 22", 0x7ffffffe47 "DEBUGINFOD_URLS=https://debuginfod.ubuntu.com ",
0x7ffffffe76 "XDG_DATA_DIRS=/usr/share/gnome:/home/geduer/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share:/var/lib/snapd/desktop",
0x7fffffff17 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin", 0x7fffffff7f "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus", 0x7fffffffb5 "SSH_TTY=/dev/pts/2",
0x7fffffffc8 "OLDPWD=/home/geduer/gelabs", 0x0, 0x21 <error: Cannot access memory at address 0x21>}
初始化函数
单步进入initilize函数,这下到了box64的核心代码了,源文件名就叫core.c。这是Linux内核喜欢使用的名字。
(gdb) n
5 x64emu_t* emu = NULL;
(gdb)
7 if (initialize(argc, argv, env, &emu, &elf_header, 1)) {
(gdb) s
initialize (argc=2, argv=0x7ffffff348, env=0x7ffffff360, emulator=emulator@entry=0x7ffffff1a8,
elfheader=elfheader@entry=0x7ffffff1b0, exec=exec@entry=1) at /home/Ada/box64/src/core.c:1729
1729 {
(gdb) n
1731 init_malloc_hook();
(gdb)
1733 init_auxval(argc, argv, environ?environ:env);
(gdb)
1735 if(getenv("BOX64_VERSION")) {
(gdb) l
单步跟踪box64的初始化过程,如果看电影一样,一个个新场景跃入眼帘。
初始化过程是复杂而且冗长的。主要的成果是创建一个代表目标架构的执行上下文。对于本试验来说,是一个名为box64context_s 的大结构体。
(gdb) pt my_context
type = struct box64context_s {
path_collection_t box64_path;
path_collection_t box64_ld_lib;
path_collection_t box64_emulated_libs;
int x64trace;
int trace_tid;
uint32_t sel_serial;
zydis_t *zydis;
void *box64lib;
int argc;
char **argv;
int envc;
char **envv;
int orig_argc;
char **orig_argv;
// 省略很多行
使用p可以观察这个结构体实例的当前取值。
(gdb) p *my_context
$6 = {box64_path = {size = 11, cap = 11, paths = 0x35603e50}, box64_ld_lib = {size = 9, cap = 11,
paths = 0x35603ae0}, box64_emulated_libs = {size = 9, cap = 12, paths = 0x35603ca0}, x64trace = 0, trace_tid = 0,
sel_serial = 1, zydis = 0x0, box64lib = 0x7ff7fff360, argc = 1, argv = 0x356022b0, envc = 0, envv = 0x0,
orig_argc = 0, orig_argv = 0x0, fullpath = 0x0, box64path = 0x0, box86path = 0x0, bashpath = 0x0, stacksz = 0,
stackalign = 0, stack = 0x0, elfs = 0x0, elfcap = 0, elfsize = 0, neededlibs = 0x0, preload = 0x0, ep = 0,
maplib = 0x35603290, local_maplib = 0x35602230, versym = 0x355f2488, globdata = 0x355f29b0, uniques = 0x355f2a28,
stacksizes = 0x0, system = 0x356032c0, exit_bridge = 65664, vsyscall = 65536, vsyscalls = {65568, 65600, 65632},
dlprivate = 0x35602280, alwrappers = 0x0, almymap = 0x0, vkwrappers = 0x0, vkmymap = 0x0, vkprocaddress = 0x0,
mutex_lock = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 2, __spins = 0, __list = {
__prev = 0x0, __next = 0x0}}, __size = '\000' <repeats 16 times>, "\002", '\000' <repeats 30 times>,
__align = 0}, mutex_trace = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 2,
__spins = 0, __list = {__prev = 0x0, __next = 0x0}},
__size = '\000' <repeats 16 times>, "\002", '\000' <repeats 30 times>, __align = 0}, mutex_tls = {__data = {
__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 2, __spins = 0, __list = {__prev = 0x0,
__next = 0x0}}, __size = '\000' <repeats 16 times>, "\002", '\000' <repeats 30 times>, __align = 0},
mutex_thread = {__data = {__lock = 0, __count = 0, __owner = 0, __nusers = 0, __kind = 2, __spins = 0, __list = {
__prev = 0x0, __next = 0x0}}, __size = '\000' <repeats 16 times>, "\002", '\000' <repeats 30 times>,
接下来的一波操作是给这个执行上下文赋值:
Looking for ./gematrix
1954 my_context->argv[0] = ResolveFileSoft(prog, &my_context->box64_path);
(gdb)
1957 my_context->box86path = box_strdup(my_context->box64path);
(gdb)
比如目标程序的全路径会被放到fullpath字段里。
(gdb) p my_context->fullpath
$7 = 0x35604c80 "/home/geduer/gelabs/gematrix/gematrix"
接下来会把目标程序加载到内存。
elfheader_t *elf_header = LoadAndCheckElfHeader(f, my_context->fullpath, 1);
然后检查目标程序需要的libc版本,如果是2.34,要做些特别对待。
box64_isglibc234 = GetNeededVersionForLib(elf_header, "libc.so.6", "GLIBC_2.34");
再下面是创建栈和建立一个emu对象。
2197 if(CalcStackSize(my_context)) {
(gdb)
2205 x64emu_t *emu = NewX64Emu(my_context, my_context->ep, (uintptr_t)my_context->stack, my_context->stacksz, 0);
(gdb)
2207 SetupInitialStack(emu);
以及为了模拟x64的一系列筹备工作。
2208 SetupX64Emu(emu, NULL);
(gdb)
2209 SetRSI(emu, my_context->argc);
(gdb)
2210 SetRDX(emu, (uint64_t)my_context->argv);
(gdb)
2211 SetRCX(emu, (uint64_t)my_context->envv);
(gdb)
2212 SetRBP(emu, 0); // Frame pointer so to "No more frame pointer"
(gdb)
2215 pthread_atfork(NULL, NULL, my_child_fork);
(gdb)
2217 thread_set_emu(emu);
(gdb)
2220 AddSymbols(my_context->maplib, elf_header);
(gdb)
下一个大动作是加载目标程序所需要的共享库。
2256 if(LoadNeededLibs(elf_header, my_context->maplib, 0, 0, 0, my_context, emu)) {
(gdb)
Using native(wrapped) libpthread.so.0
Using native(wrapped) libc.so.6
Using native(wrapped) ld-linux-x86-64.so.2
Using native(wrapped) libdl.so.2
Using native(wrapped) libutil.so.1
Using native(wrapped) librt.so.1
Using native(wrapped) libbsd.so.0
而后对库做必要的重定位处理
(gdb) n
2263 if(RelocateElf(my_context->maplib, NULL, 0, 0, elf_header)) {
(gdb)
2269 RelocateElfPlt(my_context->maplib, NULL, 0, 0, elf_header);
(gdb)
2272 RunDeferredElfInit(emu);
(gdb)
2274 RefreshElfTLS(elf_header);
(gdb)
2276 ResetSpecialCaseMainElf(elf_header);
(gdb)
2280 *emulator = emu;
(gdb)
2282 return 0;
最后把成果赋给emulator参数(返回给父函数)。
(gdb) pt **emulator
type = struct x64emu_s {
reg64_t regs[16];
x64flags_t eflags;
reg64_t ip;
sse_regs_t xmm[16];
sse_regs_t ymm[16];
mmx87_regs_t x87[8];
mmx87_regs_t mmx[8];
x87flags_t sw;
uint32_t top;
int fpu_stack;
x87control_t cw;
uint16_t dummy_cw;
mmxcontrol_t mxcsr;
fpu_ld_t fpu_ld[8];
fpu_ll_t fpu_ll[8];
uint64_t fpu_tags;
uintptr_t old_ip;
int dummy1;
deferred_flags_t df;
multiuint_t op1;
multiuint_t op2;
multiuint_t res;
multiuint_t op1_sav;
multiuint_t res_sav;
deferred_flags_t df_sav;
uint32_t *x64emu_parity_tab;
uint16_t segs[6];
uint16_t dummy_seg6;
uint16_t dummy_seg7;
uintptr_t segs_offs[6];
uint32_t segs_serial[6];
--Type <RET> for more, q to quit, c to continue without paging--
box64context_t *context;
reg64_t zero;
reg64_t *sbiidx[16];
int quit;
int error;
int fork;
int exit;
forkpty_t *forkpty_info;
emu_flags_t flags;
x64test_t test;
uint64_t scratch[200];
void *stack2free;
void *init_stack;
uint32_t size_stack;
struct __jmp_buf_tag *jmpbuf;
x64_ucontext_t *uc_link;
int type;
}
跑
冗长的初始化过程结束后,返回到main函数,下一个动作便是调用emualte:
11 return emulate(emu, elf_header);
跟踪emulate,又进入core.c
(gdb) s
emulate (emu=0x35604e90, elf_header=0x35605ea0) at /home/Ada/box64/src/core.c:2288
2288 my_context->ep = GetEntryPoint(my_context->maplib, elf_header);
(gdb) l
2283 }
2284
2285 int emulate(x64emu_t* emu, elfheader_t* elf_header)
2286 {
2287 // get entrypoint
2288 my_context->ep = GetEntryPoint(my_context->maplib, elf_header);
2289
2290 atexit(endBox64);
2291 loadProtectionFromMap();
2292
又做了一些起飞前的准备工作后,下一个关键动作是把执行的起点赋给程序指针寄存器:R_RIP。
2201 R_RIP = addr;
(gdb)
72 while(1)
(gdb) p /x addr
$12 = 0x400f62
在gdb下观察它的值,是0x400f62。
观察地址空间。
(gdb) info inferiors
Num Description Connection Executable
* 1 process 14407 1 (native) /usr/local/bin/box64
(gdb) !cat /proc/14407/maps
00010000-00011000 rwxp 00000000 00:00 0
00020000-00021000 rwxp 00000000 00:00 0
00030000-00031000 rwxp 00000000 00:00 0
00040000-00041000 rwxp 00000000 00:00 0
00050000-00051000 rwxp 00000000 00:00 0
00060000-00061000 rwxp 00000000 00:00 0
00070000-00071000 rwxp 00000000 00:00 0
00080000-00081000 rwxp 00000000 00:00 0
00400000-00403000 r-xp 00000000 103:02 524470 /home/geduer/gelabs/gematrix/gematrix
00403000-00600000 ---p 00000000 00:00 0
00600000-00607000 rw-p 00000000 00:00 0
34800000-35465000 r-xp 00000000 103:02 558469 /usr/local/bin/box64
35475000-3555b000 r--p 00c65000 103:02 558469 /usr/local/bin/box64
3555b000-3555e000 rw-p 00d4b000 103:02 558469 /usr/local/bin/box64
3555e000-3563c000 rw-p 00000000 00:00 0 [heap]
可见RIP刚好是进程里的gematrix模块。
但是这个模块是box64以文件映射方式读到内存空间的,没有正式的共享库身份,所以不在gdb的模块列表里,查找符号也找不到。
(gdb) info symbol 0x400f62
No symbol matches 0x400f62.
(gdb) info shared
From To Syms Read Shared Object Library
0x0000007ff7fbed80 0x0000007ff7fda874 Yes /lib/ld-linux-aarch64.so.1
0x0000007ff7df6dc0 0x0000007ff7f0fc20 Yes /lib/aarch64-linux-gnu/libc.so.6
0x0000007ff7d2cad0 0x0000007ff7d72960 Yes /lib/aarch64-linux-gnu/libm.so.6
0x0000007ff7cf3360 0x0000007ff7cfa348 Yes /lib/aarch64-linux-gnu/libresolv.so.2
0x0000007ff73c0730 0x0000007ff73c0824 Yes /lib/aarch64-linux-gnu/libpthread.so.0
0x0000007ff7390550 0x0000007ff7390644 Yes /lib/aarch64-linux-gnu/libdl.so.2
0x0000007ff7360690 0x0000007ff7360914 Yes /lib/aarch64-linux-gnu/librt.so.1
接下来进入一个看似没有终止的循环,那就是:
取指令,执行,取指令,执行.......
(gdb)
752 ED->q[0] = GD->q[0];
(gdb)
2190 if(ACCESS_FLAG(F_TF) || (tf_next<0)) {
(gdb)
2201 R_RIP = addr;
(gdb)
72 while(1)
(gdb)
83 emu->old_ip = addr;
(gdb) bt
#0 Run (emu=emu@entry=0x35604e90, step=<optimized out>, step@entry=0) at /home/Ada/box64/src/emu/x64run.c:83
#1 0x00000000349f4b38 in emulate (emu=0x35604e90, elf_header=<optimized out>) at /home/Ada/box64/src/core.c:2300
#2 0x00000000349f04c0 in main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>)
at /home/Ada/box64/src/main.c:11
到这里继续单步就太枯燥了,执行c,让box64跑起来。
(gdb) c
Continuing.
Matrix sample rev1.2 for tunning experiments. Improved by Raymond, based on the sample from VTune
Usage: matrix [thread_num] [algorithm no]
Collected thread no -1, algorithm no 1
Addr of buf1 = 0x7ff535f010
Offs of buf1 = 0x7ff535f180
Addr of buf2 = 0x7ff335e010
Offs of buf2 = 0x7ff335e1c0
Addr of buf3 = 0x7ff135d010
Offs of buf3 = 0x7ff135d100
Addr of buf4 = 0x7fef35c010
Offs of buf4 = 0x7fef35c140
Threads #: 8 Pthreads
如果想再停下,只要ctrl +c。
(gdb) bt
#0 0x0000007ff7e4ff9c in __futex_abstimed_wait_common64 (private=128, cancel=true, abstime=0x0, op=265,
expected=14843, futex_word=0x7fef05b110) at ./nptl/futex-internal.c:57
#1 __futex_abstimed_wait_common (cancel=true, private=128, abstime=0x0, clockid=0, expected=14843,
futex_word=0x7fef05b110) at ./nptl/futex-internal.c:87
#2 __GI___futex_abstimed_wait_cancelable64 (futex_word=futex_word@entry=0x7fef05b110, expected=14843,
clockid=clockid@entry=0, abstime=abstime@entry=0x0, private=private@entry=128) at ./nptl/futex-internal.c:139
#3 0x0000007ff7e55138 in __pthread_clockjoin_ex (threadid=549470974016, thread_return=0x7ff7ceee88, clockid=0,
abstime=0x0, block=<optimized out>) at ./nptl/pthread_join_common.c:102
#4 0x0000000034a31760 in iFLp () at /home/Ada/box64/src/wrapped/generated/wrapper.c:3377
#5 0x0000000034fa5418 in Run (emu=emu@entry=0x35604e90, step=<optimized out>, step@entry=0)
at /home/Ada/box64/src/emu/x64run.c:1493
#6 0x00000000349f7f28 in DynaRun (emu=emu@entry=0x35604e90) at /home/Ada/box64/src/dynarec/dynarec.c:180
#7 0x0000000034a0cf1c in my___libc_start_main (emu=0x35604e90,
emu@entry=<error reading variable: value has been optimized out>, main=0x400b90,
main@entry=<error reading variable: value has been optimized out>,
argc=<error reading variable: value has been optimized out>,
ubp_av=<error reading variable: value has been optimized out>,
init=<error reading variable: value has been optimized out>,
fini=<error reading variable: value has been optimized out>,
rtld_fini=<error reading variable: value has been optimized out>,
stack_end=<error reading variable: value has been optimized out>) at /home/Ada/box64/src/emu/x64run_private.c:100
#8 0x0000000034a50bd0 in iFEpippppp (emu=0x35604e90, fcn=<optimized out>)
at /home/Ada/box64/src/wrapped/generated/wrapper.c:5775
#9 0x0000000034fa5418 in Run (emu=emu@entry=0x35604e90, step=<optimized out>, step@entry=0)
at /home/Ada/box64/src/emu/x64run.c:1493
#10 0x00000000349f4b38 in emulate (emu=0x35604e90, elf_header=<optimized out>) at /home/Ada/box64/src/core.c:2300
#11 0x00000000349f04c0 in main (argc=<optimized out>, argv=<optimized out>, env=<optimized out>)
at /home/Ada/box64/src/main.c:11
观察线程:
(gdb) info threads
Id Target Id Frame
* 1 Thread 0x7ff7ff5020 (LWP 14407) "gematrix" 0x0000007ff7e4ff9c in __futex_abstimed_wait_common64 (private=128,
cancel=true, abstime=0x0, op=265, expected=14843, futex_word=0x7fef05b110) at ./nptl/futex-internal.c:57
2 Thread 0x7fef05b040 (LWP 14843) "gematrix" 0x0000000034fa6a40 in Run (emu=emu@entry=0x35636b50,
step=<optimized out>, step@entry=0) at /home/Ada/box64/src/emu/x64run.c:2196
3 Thread 0x7fee54b040 (LWP 14844) "gematrix" 0x0000000034fce65c in RunF20F (emu=emu@entry=0x35637900, rex=...,
rex@entry=..., addr=<optimized out>, step=step@entry=0x7fee54a4ac) at /home/Ada/box64/src/emu/x64runf20f.c:226
4 Thread 0x7feda3b040 (LWP 14845) "gematrix" 0x0000000034fce660 in RunF20F (emu=emu@entry=0x356386b0, rex=...,
rex@entry=..., addr=<optimized out>, step=step@entry=0x7feda3a4ac) at /home/Ada/box64/src/emu/x64runf20f.c:226
5 Thread 0x7fecf2b040 (LWP 14846) "gematrix" 0x0000000034fce660 in RunF20F (emu=emu@entry=0x35639460, rex=...,
rex@entry=..., addr=<optimized out>, step=step@entry=0x7fecf2a4ac) at /home/Ada/box64/src/emu/x64runf20f.c:226
6 Thread 0x7fec41b040 (LWP 14847) "gematrix" 0x0000000034fce660 in RunF20F (emu=emu@entry=0x3563a210, rex=...,
rex@entry=..., addr=<optimized out>, step=step@entry=0x7fec41a4ac) at /home/Ada/box64/src/emu/x64runf20f.c:226
7 Thread 0x7feb90b040 (LWP 14848) "gematrix" 0x0000000034fce660 in RunF20F (emu=emu@entry=0x3563afc0, rex=...,
rex@entry=..., addr=<optimized out>, step=step@entry=0x7feb90a4ac) at /home/Ada/box64/src/emu/x64runf20f.c:226
8 Thread 0x7feadfb040 (LWP 14849) "gematrix" 0x0000000034fa38a8 in Run (emu=emu@entry=0x3563bd70,
step=<optimized out>, step@entry=0) at /home/Ada/box64/src/emu/x64run.c:88
9 Thread 0x7fea2eb040 (LWP 14850) "gematrix" 0x0000000034fcd710 in RunF20F (emu=emu@entry=0x3563cb20,
rex=rex@entry=..., addr=4199690, step=step@entry=0x7fea2ea4ac) at /home/Ada/box64/src/emu/x64runf20f.c:31
可以看到,所有线程都是目标程序自己的,线程个数与普通执行是一样的,看来box64就是老老实实的模拟执行目标程序,并没有单独的工作线程。
切到2号工作线程,它在执行大矩阵乘法。
(gdb) thread 2
[Switching to thread 2 (Thread 0x7fef05b040 (LWP 14843))]
#0 0x0000000034fa6a40 in Run (emu=emu@entry=0x35636b50, step=<optimized out>, step@entry=0)
at /home/Ada/box64/src/emu/x64run.c:2196
2196 emit_signal(emu, SIGTRAP, (void*)addr, 1);
(gdb) bt
#0 0x0000000034fa6a40 in Run (emu=emu@entry=0x35636b50, step=<optimized out>, step@entry=0)
at /home/Ada/box64/src/emu/x64run.c:2196
#1 0x00000000349f7f28 in DynaRun (emu=emu@entry=0x35636b50) at /home/Ada/box64/src/dynarec/dynarec.c:180
#2 0x0000000034a21ec0 in pthread_routine (p=0x35636b20) at /home/Ada/box64/src/libtools/threads.c:242
#3 0x0000007ff7e537d0 in start_thread (arg=0x7ff7ff5760) at ./nptl/pthread_create.c:444
#4 0x0000007ff7ebf5cc in thread_start () at ../sysdeps/unix/sysv/linux/aarch64/clone3.S:76
现在,仍可以很方便的看到前面说的emu结构体。
(gdb) p emu
$14 = (x64emu_t *) 0x35636b50
(gdb) p *emu
$15 = {regs = {{sq = {549570439424}, q = {549570439424}, sdword = {-185374464, 127}, dword = {4109592832, 127},
sword = {26880, -2829, 127, 0}, word = {26880, 62707, 127, 0}, sbyte = "\000i\363\364\177\000\000",
byte = "\000i\363\364\177\000\000"}, {sq = {549578877232}, q = {549578877232}, sdword = {-176936656, 127},
dword = {4118030640, 127}, sword = {10544, -2700, 127, 0}, word = {10544, 62836, 127, 0},
sbyte = "0)t\365\177\000\000", byte = "0)t\365\177\000\000"}, {sq = {549511762176}, q = {549511762176},
sdword = {-244051712, 127}, dword = {4050915584, 127}, sword = {4352, -3724, 127, 0}, word = {4352, 61812, 127,
0}, sbyte = "\000\021t\361\177\000\000", byte = "\000\021t\361\177\000\000"}, {sq = {2048}, q = {2048},
sdword = {2048, 0}, dword = {2048, 0}, sword = {2048, 0, 0, 0}, word = {2048, 0, 0, 0},
(写文章很辛苦,恳请各位读者点击“在看”,也欢迎转发)
*************************************************
正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生
扫描下方二维码或者在微信中搜索“盛格塾”小程序,可以阅读更多文章和有声读物
也欢迎关注格友公众号
、