美文网首页程序的加载与链接
程序的加载与链接(一) 执行文件结构

程序的加载与链接(一) 执行文件结构

作者: 狼性刀锋 | 来源:发表于2019-11-01 16:12 被阅读0次

    先来个helloworld

    int main(int argc, const char * argv[]) {
    
        return 0;
    }
    
    

    : 这里没有包含任何头文件,也没有printf函数,目的是为了写一个尽可能简单的helloWorld

    然后我发现这个helloWorld的大小是32K,神马什么都不干还要32k,吃屎吧你。
    于是我决定扒掉它的内裤。我选择MachOView工具。

    屏幕快照 2019-11-01 上午11.00.45.png

    打头的当然是header了, magic number表明这是一个Mach-O文件,还有其他的类型比如weindows下的pe文件等等, 紧接着是cpu类型arm64,然后是具体的类型执行文件。

    简单的说操作系统它需要知道你的文件类型结构,哦你是mach-o文件啊,那按照mach-o结构进行解析,再匹配下cpu类型,耶你是x86不好意思我们不合适,88.再看下具体是类型,你是执行文件啊,好吧我给你加载到内存里让你运行,咦你是目标文件啊 ,小伙子你还太年轻下次再来。

    紧接着就是load commands,文件解析之后要加载到内存里面具体怎么加载,就看它们的了。

    屏幕快照 2019-11-01 上午11.12.55.png

    先看看LC_Command 这个命令就是将指定的文件区域加载到指定的内存区域,(这里的内存指的都是虚拟内存)
    FileSize 和 FileOffset是相对于文件而言,VM Size 和 VM Addr是相对于内存而言的,它们之间存在一定的联系,但并不是一一对应的。
    看下这个 _pagezero段就知道了,

    • FileSize = 0
    • FileOffset = 0
    • VM Size = 4294967296
    • VM Addr = 0
    • protection : 不可访问
      这段能干嘛呢,其实这一段内存并不会真正的分配,这个就是表明0 ~4294967296这段内存是不能访问的,你现在知道为什么会弹“0x0该内存不能为read了吧”

    接下来看一下LC_Command (__TEXT)段


    LC_Command (__TEXT)

    这一段是一段代码段,为什么这么说了,不单单是因为它叫text段,更重要的是
    这段的Protection = VM_PROT_EXCUTE,表明是个可执行文件,而且它只能读不能写(VM_PROT_READ)。我以前就干过把编译好的二进制代码放到数据段,然后修改指针让其运行结果导致crash的傻事,只有被标明VM_PROT_EXCUTE的段才能被cpu执行,否则等着crash吧。

    现在我们来想象一下被加载之后的内存场景:

    • 0 ~ 4294967296 不可访问
    • 4294967296 ~ 4294967296 + 32768 代码段可以被执行

    好了 现在我们假设程序以及被正确了加载到内存里面,那么如何找到main函数入口呢?之所以是假设是因为还有一些细节暂时被我屏蔽了。

    那就要用到LC_MAIN啦

    屏幕快照 2019-11-01 上午11.43.17.png

    LC_MAIN 包含了执行文件的入口信息,那么就能找到入口了啦。

    附上一张MachO结构图



    至于为什么这个文件有32k呢,是因为command结束到section的开始,中间留了很大一片的空间(约等于32k),至于为什么是这样具体还不太清楚。

    参考资料:
    https://juejin.im/post/5d5275b251882505417927b5

    相关文章

      网友评论

        本文标题:程序的加载与链接(一) 执行文件结构

        本文链接:https://www.haomeiwen.com/subject/gyrfbctx.html