Skip to content

Commit

Permalink
Optimize ELF parser
Browse files Browse the repository at this point in the history
  • Loading branch information
ntkme committed Aug 1, 2024
1 parent c3b1cf0 commit b3c8fa6
Showing 1 changed file with 50 additions and 55 deletions.
105 changes: 50 additions & 55 deletions lib/sass/elf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,49 @@ module Sass
# @see https://github.com/torvalds/linux/blob/HEAD/include/uapi/linux/elf.h
# @see https://github.com/torvalds/linux/blob/HEAD/kernel/kexec_elf.c
class ELF
module PackInfo
PACK_MAP = {
U8: 'C',
S8: 'c',
u16: 'S<',
U16: 'S>',
s16: 's<',
S16: 's>',
u32: 'L<',
U32: 'L>',
s32: 'l<',
S32: 'l>',
u64: 'Q<',
U64: 'Q>',
s64: 'q<',
S64: 'q>'
}.freeze

SIZE_MAP = PACK_MAP.to_h do |type, _|
[type, type.to_s[1..].to_i / 8]
end.freeze
end

private_constant :PackInfo

# rubocop:disable Naming/ConstantName

# 32-bit ELF base types.
Elf32_Addr = :__u32
Elf32_Half = :__u16
Elf32_Off = :__u32
Elf32_Sword = :__s32
Elf32_Word = :__u32
Elf32_Addr = :u32
Elf32_Half = :u16
Elf32_Off = :u32
Elf32_Sword = :s32
Elf32_Word = :u32

# 64-bit ELF base types.
Elf64_Addr = :__u64
Elf64_Half = :__u16
Elf64_SHalf = :__s16
Elf64_Off = :__u64
Elf64_Sword = :__s32
Elf64_Word = :__u32
Elf64_Xword = :__u64
Elf64_Sxword = :__s64
Elf64_Addr = :u64
Elf64_Half = :u16
Elf64_SHalf = :s16
Elf64_Off = :u64
Elf64_Sword = :s32
Elf64_Word = :u32
Elf64_Xword = :u64
Elf64_Sxword = :s64

# rubocop:enable Naming/ConstantName

Expand Down Expand Up @@ -60,7 +85,7 @@ class ELF
# rubocop:disable Naming/ConstantName

Elf32_Ehdr = [
[:unsigned_char, :e_ident, EI_NIDENT],
[:U8, :e_ident, EI_NIDENT],
[Elf32_Half, :e_type],
[Elf32_Half, :e_machine],
[Elf32_Word, :e_version],
Expand All @@ -77,7 +102,7 @@ class ELF
].freeze

Elf64_Ehdr = [
[:unsigned_char, :e_ident, EI_NIDENT],
[:U8, :e_ident, EI_NIDENT],
[Elf64_Half, :e_type],
[Elf64_Half, :e_machine],
[Elf64_Word, :e_version],
Expand Down Expand Up @@ -185,32 +210,25 @@ def interpreter

private

def file_class
@ehdr[:e_ident][EI_CLASS]
end

def data_encoding
@ehdr[:e_ident][EI_DATA]
end

def read_ehdr
@ehdr = { e_ident: @buffer.read(EI_NIDENT).unpack('C*') }
raise ArgumentError unless @ehdr[:e_ident].slice(EI_MAG0, SELFMAG).pack('C*') == ELFMAG

case file_class
case @ehdr[:e_ident][EI_CLASS]
when ELFCLASS32
Elf32_Ehdr
when ELFCLASS64
Elf64_Ehdr
else
raise ArgumentError
end.drop(1).to_h do |field|
[field[1], read1(field[0])]
end.merge!(@ehdr)
end.drop(1).each do |field|
@ehdr[field[1]] = read1(field[0])
end
@ehdr
end

def read_phdr
case file_class
case @ehdr[:e_ident][EI_CLASS]
when ELFCLASS32
Elf32_Phdr
when ELFCLASS64
Expand All @@ -222,35 +240,12 @@ def read_phdr
end
end

def explicit_endian
case data_encoding
def read1(type)
case @ehdr[:e_ident][EI_DATA]
when ELFDATA2LSB
'<'
@buffer.read(PackInfo::SIZE_MAP[type]).unpack1(PackInfo::PACK_MAP[type])
when ELFDATA2MSB
'>'
else
raise ArgumentError
end
end

def read1(type)
case type
when :__u8
@buffer.read(1).unpack1('C')
when :__u16
@buffer.read(2).unpack1("S#{explicit_endian}")
when :__u32
@buffer.read(4).unpack1("L#{explicit_endian}")
when :__u64
@buffer.read(8).unpack1("Q#{explicit_endian}")
when :__s8
@buffer.read(1).unpack1('c')
when :__s16
@buffer.read(2).unpack1("s#{explicit_endian}")
when :__s32
@buffer.read(4).unpack1("l#{explicit_endian}")
when :__s64
@buffer.read(8).unpack1("q#{explicit_endian}")
@buffer.read(PackInfo::SIZE_MAP[type]).unpack1(PackInfo::PACK_MAP[type.upcase])
else
raise ArgumentError
end
Expand Down

0 comments on commit b3c8fa6

Please sign in to comment.