Golang中如何计算ELF文件的大小

Golang中如何计算ELF文件的大小 如何在Go中计算ELF可执行文件的大小?

我正在寻找类似以下C代码的解决方案:

/*

使用以下命令编译:

gcc elfsize.c -o elfsize

示例:

ls -l						126584

目前我正在使用Cgo,但我更倾向于纯Go的解决方案。

4 回复

非常感谢 @hollowaykeanho。这是一个非常有用的示例和解释。我欠你一个大人情。

更多关于Golang中如何计算ELF文件的大小的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


欢迎来到 Go 论坛! 🚀🎆


probono: 如何在 Go 中计算 ELF 可执行文件的大小?

我不太明白你的意思,ls -l 不是就能显示二进制文件的大小吗?还是说你想知道总大小的细分构成?

标准库里有一个 elf 包。这个会有帮助吗?elf package - debug/elf - Go Packages

hollowaykeanho:

我不太明白你的意思,ls -l 应该能显示二进制文件的大小,对吧?还是说你需要从总大小中分解出各部分的大小?

感谢你的热情欢迎。

我之前没有提到的是,我需要使用 ELF 头文件中的信息来计算 ELF 二进制文件的大小,而不是通过查看磁盘上的文件大小,因为磁盘上的文件在 ELF 数据后面附加了随机数据。

其他语言的代码示例:

由于我真的是刚刚开始学习 Go,我还不太清楚如何将其翻译成 Go 代码。

在Go中计算ELF文件大小可以通过解析ELF头部和程序头部表来实现。以下是一个纯Go的实现示例:

package main

import (
    "debug/elf"
    "fmt"
    "os"
)

func getELFSize(filename string) (uint64, error) {
    f, err := elf.Open(filename)
    if err != nil {
        return 0, err
    }
    defer f.Close()

    // 获取最后一个程序段的结束位置
    var maxOffset uint64
    for _, prog := range f.Progs {
        end := prog.Off + prog.Filesz
        if end > maxOffset {
            maxOffset = end
        }
    }

    // 检查是否有节头表
    if f.SectionHeaderOffset > 0 {
        // 节头表通常位于文件末尾
        shdrEnd := f.SectionHeaderOffset + uint64(f.SectionHeaderSize)*uint64(f.SectionHeaderNum)
        if shdrEnd > maxOffset {
            maxOffset = shdrEnd
        }
    }

    return maxOffset, nil
}

func main() {
    if len(os.Args) < 2 {
        fmt.Println("Usage: go run main.go <elf_file>")
        return
    }

    size, err := getELFSize(os.Args[1])
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        return
    }

    fmt.Printf("ELF file size: %d bytes\n", size)
}

如果需要更精确的计算(包括对齐填充),可以使用以下增强版本:

func getELFSizeExact(filename string) (uint64, error) {
    f, err := elf.Open(filename)
    if err != nil {
        return 0, err
    }
    defer f.Close()

    // 获取文件信息以验证大小
    fileInfo, err := os.Stat(filename)
    if err != nil {
        return 0, err
    }

    // 方法1:使用程序段计算
    var calculatedSize uint64
    for _, prog := range f.Progs {
        end := prog.Off + prog.Filesz
        if end > calculatedSize {
            calculatedSize = end
        }
    }

    // 方法2:考虑节头表
    if f.SectionHeaderOffset > 0 {
        shdrSize := uint64(f.SectionHeaderSize) * uint64(f.SectionHeaderNum)
        shdrEnd := f.SectionHeaderOffset + shdrSize
        if shdrEnd > calculatedSize {
            calculatedSize = shdrEnd
        }
    }

    // 确保至少包含ELF头部
    if calculatedSize < 64 { // ELF头部最小为64字节
        calculatedSize = 64
    }

    // 验证计算的文件大小与实际文件大小
    actualSize := uint64(fileInfo.Size())
    if calculatedSize > actualSize {
        return actualSize, nil
    }

    return calculatedSize, nil
}

编译和运行示例:

# 编译
go build -o elfsize main.go

# 运行
./elfsize /bin/ls

这个实现使用了Go标准库中的debug/elf包,它提供了完整的ELF文件解析功能。计算逻辑基于ELF规范:文件大小由最后一个程序段或节头表的结束位置决定,取两者中的较大值。

回到顶部