龙芯新旧世界是龙芯基于 LoongArch 架构形成的两套软件生态体系,主要差异体现在 ABI 规范、软件兼容性及开发策略上:
1. 新旧世界的核心区别
- 旧世界(ABI1.0):早期为快速构建生态,沿用部分 MIPS 遗留设计,指令集未完全脱离 MIPS 兼容模式。其内核由龙芯独立维护(版本多为 4.19、5.4 等),优先支持商业软件(如 QQ、微信),适配发行版包括 Loongnix、麒麟、统信等。旧世界生态闭源程度较高,更新依赖龙芯内部推动。
- 新世界(ABI2.0):完全遵循开源社区标准重构 LoongArch 指令集,彻底摒弃 MIPS 兼容模式,内核版本更高(≥5.19),由开源社区协作维护。新世界对开源软件兼容性更优(如高版本浏览器、Archlinux 等),并通过 liblol 兼容层支持旧世界商业软件运行。未来旧世界将逐步向新世界迁移,3A6000 及以上 CPU 已实现固件级兼容。
2. 命令行判断方法
通过检测系统原生二进制文件的 ELF 头部标识,可快速区分新旧世界:
hexdump -s 48 -C /usr/bin/sh | head -n 1 | awk '{print $2}'
- 返回值为 43 表示新世界(ABI2.0)
- 返回值为 03 表示旧世界(ABI1.0)
此方法通过解析 Shell 解释器的 ELF 头特定字段(e_flags),直接反映 ABI 版本,较内核版本判断更为可靠。若需自动化脚本实现,可将该命令集成至环境检测逻辑中。
3. 在C#中的判断方法
基于上述规则,使用C#判断龙芯新旧世界平台
/// <summary>
/// Helper class for runtime environment information, especially for LoongArch64 architecture.
/// </summary>
internal static class RuntimeInformationHelper
{
// Pre-compile the regex pattern for kernel version matching
private static readonly Regex KernelVersionRegex = new(
@"^(?<major>0|[1-9]\d*)\.(?<minor>0|[1-9]\d*)\.(?<patch>0|[1-9]\d*)(?:-(?<prerelease>(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+(?<buildmetadata>[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$",
RegexOptions.Compiled);
private static readonly Lazy<bool> _isABI1 = new(DetermineIsABI1);
// Version threshold for ABI2
private static readonly Version Abi2MinVersion = new(5, 19);
// Common executable files to read ELF mark from
private static readonly string[] ElfExecutables = { "/usr/bin/sh", "/bin/sh", "/usr/bin/bash" };
/// <summary>
/// Determines if the current runtime is using ABI1 on LoongArch64 Linux.
/// </summary>
/// <returns>True if running on ABI1, false otherwise.</returns>
public static bool IsABI1() => _isABI1.Value;
/// <summary>
/// Determines if the current runtime is LoongArch64 architecture on Linux OS.
/// </summary>
/// <returns>True if running on LoongArch64 Linux, false otherwise.</returns>
public static bool IsLoongArch64Linux() =>
RuntimeInformation.ProcessArchitecture == Architecture.LoongArch64 &&
RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
/// <summary>
/// Determines if the current LoongArch64 Linux environment is using ABI1.
/// </summary>
/// <returns>True if ABI1 is detected, false otherwise.</returns>
private static bool DetermineIsABI1()
{
// Quick check - if not on LoongArch64 Linux, definitely not ABI1
if (!IsLoongArch64Linux())
{
return false;
}
// Strategy 1: Check ELF header mark
string elfMark = ReadELFMark();
if (elfMark == "03") return true;
if (elfMark == "43") return false;
// Strategy 2: Check kernel version
Version? kernelVersion = DetectKernelVersion();
if (kernelVersion != null)
{
return kernelVersion < Abi2MinVersion;
}
// Strategy 3: Check OS description
return RuntimeInformation.OSDescription.Contains("Loongnix GNU/Linux 20");
}
/// <summary>
/// Detects the kernel version using available methods.
/// </summary>
/// <returns>The kernel version or null if detection failed.</returns>
private static Version? DetectKernelVersion()
{
// Try uname syscall first
string? kernelVersionStr = GetLinuxKernelVersionByUname();
if (TryMatchKernelVersion(kernelVersionStr, out var version))
{
return version;
}
// Fall back to process execution
kernelVersionStr = GetLinuxKernelVersionByProcess();
TryMatchKernelVersion(kernelVersionStr, out version);
return version;
}
/// <summary>
/// Reads the ELF header mark from common executable files.
/// </summary>
/// <returns>The ELF mark as a hexadecimal string or empty string if reading failed.</returns>
private static string ReadELFMark()
{
foreach (var filePath in ElfExecutables)
{
if (!File.Exists(filePath))
{
continue;
}
try
{
using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
fs.Seek(48, SeekOrigin.Begin);
int byteValue = fs.ReadByte();
if (byteValue != -1)
{
string hexValue = byteValue.ToString("X2");
if (hexValue is "43" or "03")
{
return hexValue;
}
}
}
catch (Exception)
{
// Continue trying with next file
}
}
return string.Empty;
}
/// <summary>
/// Attempts to parse a kernel version string into a Version object.
/// </summary>
/// <param name="kernelVersion">The kernel version string.</param>
/// <param name="version">The parsed Version object.</param>
/// <returns>True if parsing succeeded, false otherwise.</returns>
private static bool TryMatchKernelVersion(string? kernelVersion, out Version? version)
{
version = null;
if (string.IsNullOrWhiteSpace(kernelVersion))
{
return false;
}
Match match = KernelVersionRegex.Match(kernelVersion);
if (match.Success &&
match.Groups.TryGetValue("major", out Group? major) && !string.IsNullOrWhiteSpace(major?.Value) &&
match.Groups.TryGetValue("minor", out Group? minor) && !string.IsNullOrWhiteSpace(minor?.Value) &&
Version.TryParse($"{major.Value}.{minor.Value}", out Version? parsedVersion))
{
version = parsedVersion;
return true;
}
return false;
}
/// <summary>
/// Gets the Linux kernel version by executing the uname command.
/// </summary>
/// <returns>The kernel version string or empty string if execution failed.</returns>
private static string GetLinuxKernelVersionByProcess()
{
try
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "uname",
Arguments = "-r",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
string output = process.StandardOutput.ReadToEnd().Trim();
process.WaitForExit();
return output;
}
catch (Exception)
{
return string.Empty;
}
}
[DllImport("libc", SetLastError = true)]
private static extern int uname(IntPtr buf);
/// <summary>
/// Gets the Linux kernel version using the uname system call.
/// </summary>
/// <returns>The kernel version string or empty string if the call failed.</returns>
private static string? GetLinuxKernelVersionByUname()
{
IntPtr buf = IntPtr.Zero;
try
{
buf = Marshal.AllocHGlobal(400);
if (uname(buf) == 0)
{
return Marshal.PtrToStringAnsi(buf + 130);
}
return string.Empty;
}
catch (Exception)
{
return string.Empty;
}
finally
{
if (buf != IntPtr.Zero)
{
Marshal.FreeHGlobal(buf);
}
}
}
}
注:部分旧世界系统可能通过兼容层运行新世界软件,但原生编译的二进制仍遵循上述规则。开发跨生态应用时,建议优先采用新世界工具链以确保长期兼容性。
文章评论