WSL 1 的入口点是什么?

What is the entry point for WSL 1?

假设我们有一个静态链接的 Linux 可执行文件。

我应该如何在导入的 tar.gz 中命名它,以便 WSL 1 默认情况下 运行 它在创建和启动时像:

# import an archive as a WSL distro
wsl --import static tmp-root-dir static.tar.gz
# boot distro to a default app??
wsl -d static

PS WSL 使用自己专有的启动进程,似乎不使用传统的 Unix /sbin/init.

简答:

最小的可引导(无错误或警告)WSL rootfs 将包含三个文件:

  • /main:您的 statically-linked 申请。只要名称与 passwd.
  • 中的名称相匹配,它就可以随意命名。
  • /etc/passwd:定义为默认用户加载的应用程序(即shell)。
  • /etc/wsl.conf:抑制正常的 WSL 功能并(可选)定义 non-root 用户。

更多详情:

这可能不完全您想要的,但它有望满足您的需求。

首先,WSL 的入口点(Linux ELF 二进制文件第一次在实例中启动)似乎是它的 /init 二进制文件,除了一些“ normal" Linux 初始化进程任务,设置一些 Windows-interop 功能。据我所知,目前无法更改。据我所知,对于 WSL1,它是在启动 WSL 实例时由 LXSS 管理器注入到实例中的。

注意:WSL2 在这方面可能 略有不同,因为它似乎确实使用 kernel-processed initrd 来加载 /init。可以覆盖内核 command-line,但这会影响 所有 WSL2 实例,因此它可能不是一个实用的解决方案。

从你的问题中不太清楚你是否希望“默认应用程序”:

  • 运行 作为默认 application/shell 每次 wsl -d static 是 运行,即使它已经是 运行ning.
  • 或者在第一次启动 WSL1 实例时只 运行 一次。

我相信你正在寻找第一个选项。

运行 作为默认应用

在第一种情况下,标准的 WSL1 /init 流程可能会让您到达需要的位置。作为启动的一部分,如您所料,它读取 /etc/passwd 以确定要启动的用户 shell。它还读取 /etc/wsl.conf 以确定默认用户 ID(但如果在 wsl.conf 中没有设置默认用户,则回退到注册表)。

因此,要启动不同的应用程序(我们称之为 main),您可以:

  • 将二进制文件放在映像的根目录中。

  • 在single-line/etc/passwd:

    中将应用设置为root用户的“shell”
    user:x:1000:1000:user:/:/main
    

    Side-note 这也将主目录设置为 / 因此我们不必创建另一个目录。

  • 定义一个etc/wsl.conf,内容如下:

    [user]
    default=user
    
    [automount]
    enabled=false
    mountFsTab=false
    
    [interop]
    appendWindowsPath=false
    

    这将阻止 WSL 执行以下启动任务,如果没有额外的图像支持,这会产生错误:

    • 正在将 Windows 驱动器安装到实例中
    • 正在尝试处理 /etc/fstab(因为图像中没有 mount 命令)。
    • 追加 Windows 路径(因为我们的实例无法访问 Windows 驱动器)

    它还将默认用户设置为我们在 /etc/passwd 中创建的 UID 1000 用户。这不是绝对必要的 - 在这个 single-use 实例中,运行ning 作为 root 可能没有关系,但我已经将 non-root 用户作为“最佳实践”。

应该是这样。最小的可启动 WSL rootfs 将仅包含这三个文件:

/etc/wsl.conf
/etc/passwd
/main

这将适用于 WSL1 和 WSL2,但对于 WSL2,您应该使用 wsl ~ -d static 调用以确保它不会尝试在它可以启动的 Windows 驱动器上启动' 访问。否则,您将收到一个初始化错误,但您的应用程序仍将被调用。

运行一次

如果您正在寻找可以在实例首次启动时启动守护进程的东西,那么我在 . If you are on Windows 11, then there's a built-in mechanism via /etc/wsl.conf. Otherwise, on Windows 10, you'll probably need to include some binary that can handle conditional logic. Something like execline 中记录的一些替代方案可能是完美的为此,但至少我在 WSL2 下遇到过问题,我不确定它是否会 运行 在 WSL1 下(但它可能)。

Side-note 对于 WSL1/musl

musl 是常用的替代 libc 实现。例如,Rust(AFAICT)只能使用 musl 生成真正的 statically-linked 可执行文件。但是请注意,WSL1 不能 运行 musl-based 静态链接二进制文件。

WSL2 可以很好地处理它们。

我设法让它工作了。最初我在创建 TAR 存档时错过了应用程序上的可执行位。

采用标准的 64 位汇编:

.data
msg:
  .ascii "Hello, world!\n"
  .set len, . - msg

.text

.globl _start
_start:
  # write
  mov  ,   %rax
  mov  ,   %rdi
  mov  $msg, %rsi
  mov  $len, %rdx
  syscall

  # exit
  mov  , %rax
  xor  %rdi, %rdi
  syscall

并创建一个最小的 WSL 系统:

wsl as -64 -o minimal.o minimal.s
wsl ld -melf_x86_64 -o minimal minimal.o
tar czf minimal.tar.gz \
  --mode=a=rx \
  --xform='s#^minimal#/[=11=]#' minimal
wsl --import minimal rootfs-minimal minimal.tar.gz --version 1
wsl --list
wsl -d minimal -e /minimal

要使可执行文件 默认(将 wsl -d minimal -e /minimal 缩短为 wsl -d minimal),我们需要一个额外的文件 /etc/passwd:

root:x:0:0:root:/root:/minimal

此文件的第一行 确定默认用户以及可执行文件(入口点)的路径,除非您使用 /etc/wsl.conf:[=21= 覆盖用户]

[user]
default=user

基本上 WSL 1 只将 2 个文件视为魔法文件(除了忽略 /sbin/init):

  • /etc/wsl.conf
  • /etc/passwd