文件压缩-42的魅力

让我们以一个非常简单的程序为例,一个什么都不做的程序 将数字返回给操作系统。为什么不呢?毕竟,Unix 已经附带了不少于两个这样的程序:true 和 假。由于已经取了 0 和 1,我们将使用数字 42。

所以,这是我们的第一个版本:

 /* tiny.c */int main(void) { return 42; }

我们可以像这样编译和测试:

 $ gcc -Wall tiny.c$ ./a.out ; echo $?//返回返回值42

图示操作如下:

所以。它有多大?它有多大,好吧,在我的机器上,我得到:

  $ wc -c a.out3998 a.out
(你的可能会有所不同。诚然,这是相当小的 今天的标准,但几乎可以肯定比它需要的要大。

 我的机器上结果如下:

 显而易见的第一步是剥离可执行文件:

 这当然是一个进步。对于下一步,怎么样 优化?

这在理论上也有所帮助,但实际上:几乎没有任何需要优化的东西。 

我们似乎不太可能做太多其他事情来缩小 单语句 C 程序。我们将不得不把 C 抛在后面,然后 请改用汇编程序。希望这将减少所有额外的内容 C 程序自动产生的开销。

所以,进入我们的第二个版本。我们需要做的就是从 main() 中。在汇编语言中,这意味着函数应设置 累加器 EAX 设置为 42,然后返回:

首先建立.asm文件

gedit tiny.asm

内容如下: 

 ; tiny.asmBITS 32GLOBAL mainSECTION .textmain:mov     eax, 42ret

 编译指令如下:

 $ nasm -f elf tiny.asm$ gcc -Wall -m32 -s tiny.o$ ./a.out ; echo $?42

结果如下:

这里可以注意,编译的时候报了一个错误:

问题原因:
在64位系统下去编译32位的目标文件,这样是非法的。

解决方案:
用”-m32”强制用32位ABI去编译,即可编译通过。

查看当前大小如下:从14328到13656减少了672. 

 

好吧,问题是我们仍然会产生大量的开销 使用 main() 接口。链接器仍在添加一个接口 我们的操作系统,正是该接口实际上调用了 main()。所以 如果我们不需要它,我们如何解决这个问题?

默认情况下,链接器使用的实际入口点是符号 名称为 _start。当我们与gcc链接时,它会自动 包括一个 _start 例程,一个设置 argc 和 argv 的例程,以及其他 things,然后调用 main()。 

所以,让我们看看我们是否可以绕过它,并定义我们自己的_start 常规

  ; tiny.asmBITS 32GLOBAL _startSECTION .text_start:mov     eax, 42ret

gcc 会做我们想做的事吗?

不。好吧,实际上,是的,它会的,但首先我们需要学习如何提问 为了我们想要的。

碰巧 gcc 识别一个名为 -nostartfiles 的选项。 从 gcc 信息页面:

-nostartfiles
在以下情况下不要使用标准系统启动文件 连接。标准库正常使用。

啊哈!现在让我们看看我们能做些什么:

好吧,gcc 没有抱怨,但该程序不起作用。发生了什么 错?

问题在于我们把_start当作一个 C 函数来对待, 并试图从中返回。实际上,它根本不是一个功能。 它只是链接器用来定位的目标文件中的一个符号 程序的切入点。当我们的程序被调用时,它就会被调用 径直。如果我们看一下,我们会看到顶部的值 堆栈中的数字是 1,这当然非常 un-address-like。事实上,堆栈上的是我们程序的 argc 价值。在此之后是 argv 数组的元素,包括 终止 NULL 元素,后跟 envp 的元素。这就是 都。堆栈上没有返回地址。

那么,_start是如何退出的呢?好吧,它调用了 exit() 函数! 毕竟,这就是它的用途。

实际上,我撒谎了。它真正做的是调用 _exit() 函数。 (请注意前导下划线。exit() 是完成一些 代表流程的任务,但这些任务永远不会 started,因为我们绕过了库的启动代码。所以我们 还需要绕过库的关机代码,直接转到 操作系统的关机处理。

所以,让我们再试一次。我们将调用 _exit(),它是一个 函数,该函数采用单个整数参数。因此,我们需要做的就是 将数字推送到堆栈上并调用该函数。(我们还需要 将 _exit() 声明为外部。这是我们的组装:

  ; tiny.asmBITS 32EXTERN _exitGLOBAL _startSECTION .text_start:push    dword 42call    _exit

 查看现在的结果:减少了588字节,变成了13068

嗯......那么还有什么其他的 GCC 有有趣的晦涩选项吗?

好吧,这个,紧跟在 -nostartfiles 之后 文档,当然是引人注目的:

-nostdlib
不要使用标准的系统库和启动链接时的文件。只有您指定的文件才会 传递给链接器。

这值得研究:

哎呀。没错...... 毕竟,_exit() 是一个库函数。 它必须从某个地方填写。

好。但可以肯定的是,我们不需要 libc 的帮助来结束一个程序, 我们呢?

不,我们没有。如果我们愿意抛开所有伪装 可移植性,我们可以使我们的程序退出而不必链接 别的东西。不过,首先,我们需要知道如何制作一个系统 在 Linux 下调用

与大多数操作系统一样,Linux 为 它通过系统调用托管的程序。这包括打开等内容 一个文件,读取和写入文件句柄 - 当然,还有 关闭进程。

Linux 系统调用接口是一条指令:int 0x80。 所有系统调用都通过此中断完成。要进行系统调用, EAX 应包含一个数字,用于指示正在进行哪个系统调用 调用,其他寄存器用于保存参数(如果有)。 如果系统调用采用一个参数,则该参数将位于 ebx 中;一个系统 具有两个参数的调用将使用 EBX 和 ECX。同样,edx、esi 和 如果需要第三个、第四个或第五个参数,则使用 EDI, 分别。从系统调用返回后,eax 将包含 返回值。如果发生错误,eax 将包含一个负值, 绝对值表示错误。

不同系统调用的号码列在 /usr/include/asm/unistd.h。快速浏览一下就会告诉我们,出口 系统调用被分配为数字 1。像 C 函数一样,它需要 一个参数,返回到父进程的值,等等 将进入 EBX。

我们现在知道了创建下一个版本所需的所有信息。 程序,一个不需要任何外部函数帮助的程序 工作

 ; tiny.asmBITS 32GLOBAL _startSECTION .text_start:mov     eax, 1mov     ebx, 42  int     0x80

查看结果,从减少了288字节,变成了12780 

所以。。。我们还能做些什么来让它变得更小吗?

使用更短的指令怎么样?

如果我们为汇编代码生成一个列表文件,我们将找到 以后:

 00000000 B801000000        mov        eax, 100000005 BB2A000000        mov        ebx, 420000000A CD80              int        0x80

好吧,哎呀,我们不需要初始化所有 ebx,因为操作 系统将只使用最低的字节。单独设置 bl 将是 足够了,并且将占用两个字节而不是五个字节。

我们还可以通过将 eax 设置为 1 来将其 xor'ing 为零,然后使用 单字节增量指令;这将节省两个字节。

  00000000 31C0              xor        eax, eax00000002 40                inc        eax00000003 B32A              mov        bl, 4200000005 CD80              int        0x80

我认为可以肯定地说,我们不会这样做 编程任何比这更小的程序。

顺便说一句,我们不妨停止使用 gcc 来链接我们的可执行文件, 鉴于我们没有使用它的任何附加功能,而只是 调用链接器 LD,我们自己:

关于为 Linux 创建真正 Teensy ELF 可执行文件的旋风教程 (muppetlabs.com)

后续的内容都是按着这篇文章写得,实现之后实在懒得写博客了。。。。

最后的实现压缩成45字节

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/17519.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ComfyUI 基础教程:界面介绍/文生图工作流

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里,订阅后可阅读专栏内所有文章。 大家好,我是水滴~~ 本文将介绍 ComfyUI 的主要界面,包括:工作流区域、操作面板、基础操作和快捷键,并详…

ctfshow web 月饼杯

web1_此夜圆 <?php error_reporting(0);class a {public $uname;public $password;public function __construct($uname,$password){$this->uname$uname;$this->password$password;}public function __wakeup(){if($this->passwordyu22x){include(flag.php);echo…

如何处理 Google Chrome中的代理服务器错误?

如果您在 Google Chrome 浏览器中遇到代理服务器错误&#xff0c;您可以采取一些步骤来排除故障并解决问题。代理服务器充当您的设备和互联网之间的中介&#xff0c;与其相关的错误有时会破坏您的浏览体验。以下是帮助您解决该问题的一些步骤&#xff1a; 1. 检查您的互联网连接…

QListWidget详解

QListWidget详解 QListWidget 是 PyQt5 中一个方便的部件&#xff0c;用于创建和管理列表。它继承自 QListView&#xff0c;并提供了一些高级功能&#xff0c;使得添加和管理列表项更加简单。以下是 QListWidget 的详解&#xff0c;包括基本用法、主要方法和属性以及如何与其他…

Unity Apple Vision Pro 开发(一):开发前期准备【软硬件要求 | 开发者模式 | 无线调试打包】

文章目录 &#x1f4d5;教程说明&#x1f4d5;硬件要求&#x1f4d5;软件要求⭐Xcode 15.2 及以上⭐visionOS 1.0 (21N301) SDK 或者更高版本⭐Unity 2022 LTS for Apple Silicon (2022.3.18f1及以上的版本)⭐Unity Pro/Unity Enterprise/Unity Industry的授权许可证 &#x1f…

最新斗音评论区截流拓客,自动引流【引流软件+使用教程】

面对社交媒体的蓬勃生长&#xff0c;加粉和拓展客户群成为品牌及个体的当务之急。新推出的一款技术工具恰到好处地迎合了这一需求&#xff0c;提供了一个多功能、适用性强的增粉与互动解决方案。该工具与抖音平台的所有版本兼容&#xff0c;消除了对特定版本的依赖。 利用这一…

selenium自动化测试环境搭建

1.下载安装python python的下载与安装-CSDN博客 2.下载安装pycharm pycharm免费下载安装教程_pycharmcommunity下载-CSDN博客 3.下载安装浏览器驱动 chrome浏览器官网下载网址 https://www.google.cn/chrome/?standalone1&platformwin64 Selenium安装WebDriver最新…

预训练大模型

参考代码&#xff1a;https://github.com/LlamaFamily/Llama-Chinese

Python 应用开发:Streamlit 布局篇(容器布局)

st.columns 以并列方式插入容器。 插入若干并排排列的多元素容器&#xff0c;并返回一个容器对象列表。 要在返回的容器中添加元素&#xff0c;可以使用 with 符号&#xff08;首选&#xff09;或直接调用返回对象的方法。请参见下面的示例。 列只能放置在其他列的内部&…

你还别不信,停电停网也能玩超级玛丽,还能自己编辑关卡和地图呢!

网管小贾 / sysadm.cc 死神正了然无趣地翻阅着人间档案&#xff0c;突然&#xff0c;它眼前一亮。 艾瑞克牛&#xff0c;社畜属&#xff0c;躺平体质&#xff0c;1996年9月6日出生&#xff0c;现年59岁&#xff0c;剩余寿命1小时15分08秒…… 当晚&#xff0c;在不足20平的出…

【Unity之FGUI】Fairy GUI面板的创建相关

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;就业…

vue组件的基本使用方法

组件 【1】组件是什么&#xff1f; 组件就是&#xff1a;扩展 HTML 元素&#xff0c;封装可重用的代码&#xff0c;目的是复用例如&#xff1a;有一个轮播图&#xff0c;可以在很多页面中使用&#xff0c;一个轮播有js&#xff0c;css&#xff0c;html组件把js&#xff0c;cs…

【移动云】5G时代——你我的智慧云

文章目录 0.引言1.移动云简介2.移动云学习资源3.移动云产品介绍3.1 大数据—数据可视化&#xff08;DataInsight&#xff09;3.1.1 应用场景3.1.2 产品基本架构3.1.3 优势 3.2 云主机ECS3.2.1 云主机ECS优势3.2.2 云主机主要功能3.2.3 应用场景 4.移动云解决方案4.1 热门案例1&…

男士内裤哪个品牌好穿舒服?适合夏季的五款男士内裤推荐

很多男性对内裤的不重视&#xff0c;似乎是与生俱来的&#xff0c;错把“糙汉”当“硬汉”。特别是一直以来都由女性包办内裤的男士&#xff0c;经常是不合适也勉强穿着。即使是生活条件不断提升的今天&#xff0c;还是有不少男士表面光鲜亮丽&#xff0c;对内裤反而不太讲究。…

解读:Mint Blockchain 最新路线图,释放 NFT 生态重磅发展计划

作者&#xff1a;Mint Ecosystem 关于 Mint Blockchain&#xff1a;Mint Blockchain 是一个以太坊原生 L2 网络&#xff0c;核心是发展 NFT 生态和产业&#xff0c;促进 NFT 领域的 Mass Adoption 产生。MintCore 团队致力于将 Mint Blockchain 打造成一个围绕服务 NFT 资产的…

SqlServer 2016 2017 2019安装失败-无法找到数据库引擎启动句柄

SqlServer 2016 2017 2019安装失败-无法找到数据库引擎启动句柄 出现以上问题的原因是因为系统账户无法操作数据库引擎服务。需要调整权限。 按照以下步骤解决&#xff0c;成功完成安装&#xff0c;已亲测&#xff1a; 1、如果您已经安装了相同版本的SQL Server&#xff0c;…

数据结构算法题day03

数据结构算法题day03 题目 题目 2.设计一个高效算法&#xff0c;将顺序表L的所有元素逆置&#xff0c;要求算法的空间复杂度为O(1)算法思想&#xff1a; 1、常规的解法&#xff1a; Void reverse (sqlist &L){Elemtype temp; //辅助变量for(i 0,i < L.length; i){temp…

基于NAMUR开放式架构(NOA)的工业设备数据采集方案

一 NAMUR开放式架构 传统自动化金字塔结构的优越性在过去许多年里已被证明。然而&#xff0c;传统的自动化金字塔在获取和利用对物联网和工业4.0有价值的数据方面却存在一定挑战。这是因为传统系统通常是封闭的&#xff0c;数据访问受到限制&#xff0c;难以集成到新的数字化解…

剖析【C++】——类与对象(中)——小白篇—超详解

目录 1.类的6个默认成员函数&#xff1a; 1. 默认构造函数&#xff08;Default Constructor&#xff09; 2. 析构函数&#xff08;Destructor&#xff09; 3. 拷贝构造函数&#xff08;Copy Constructor&#xff09; 4. 拷贝赋值运算符&#xff08;Copy Assignment Operato…

Docker部署后的中文乱码问题

本地和服务器上面生成图片文字多没有乱码&#xff0c;但是服务部署到docker上面就开始出现乱码。排查了一下发现是docker上缺少相应的中文字体&#xff0c;添加字体即可解决。 1.在网站上找到相关资源并下载字体-字体下载-字体下载大全-字体免费下载|字体下载 2.上传到服务器 …