melf 1.0.0 → 1.0.1
raw patch · 40 files changed
+3077/−416 lines, 40 filesbinary-addedPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.Elf: elfFindSectionByName :: forall a m. (SingI a, MonadThrow m) => [ElfXX a] -> String -> m (ElfXX a)
Files
- ChangeLog.md +8/−0
- README.md +4/−8
- examples/AsmAArch64.hs +326/−0
- examples/AsmAarch64.hs +0/−258
- examples/DummyLd.hs +63/−0
- examples/Examples.hs +5/−5
- examples/ForwardLabel.hs +1/−1
- examples/HelloWorld.hs +1/−1
- examples/MkExe.hs +0/−45
- examples/MkObj.hs +0/−89
- examples/README_ru.md +706/−0
- examples/forwardLabelExe.dump.golden +27/−0
- examples/forwardLabelExe.layout.golden +8/−0
- examples/helloWorldExe.dump.golden +25/−0
- examples/helloWorldExe.layout.golden +8/−0
- examples/helloWorldObj.o.dump.golden +58/−0
- examples/helloWorldObj.o.layout.golden +12/−0
- melf.cabal +30/−5
- src/Data/Elf.hs +3/−2
- src/Data/Elf/PrettyPrint.hs +3/−1
- src/Data/Internal/Elf.hs +11/−0
- testdata/orig/bloated binary
- testdata/orig/tiny binary
- testdata/orig/vdso binary
- tests/Golden.hs +4/−1
- tests/testdata/orig/bloated.elf.golden +483/−0
- tests/testdata/orig/bloated.elf_header.golden +15/−0
- tests/testdata/orig/bloated.header.golden +437/−0
- tests/testdata/orig/bloated.layout.golden +82/−0
- tests/testdata/orig/bloated.strtable.golden +29/−0
- tests/testdata/orig/tiny.elf.golden +45/−0
- tests/testdata/orig/tiny.elf_header.golden +15/−0
- tests/testdata/orig/tiny.header.golden +66/−0
- tests/testdata/orig/tiny.layout.golden +13/−0
- tests/testdata/orig/tiny.strtable.golden +3/−0
- tests/testdata/orig/vdso.elf.golden +271/−0
- tests/testdata/orig/vdso.elf_header.golden +15/−0
- tests/testdata/orig/vdso.header.golden +238/−0
- tests/testdata/orig/vdso.layout.golden +46/−0
- tests/testdata/orig/vdso.strtable.golden +16/−0
ChangeLog.md view
@@ -1,3 +1,11 @@+1.0.1+=====++- Rename Aarch64 -> AArch64+- Rework examples: fuse `MkObj` into `AsmAArch64`, rewrite `MkExe` as `DummyLd`+- Implement `elfFindSectionByName`+- Add test data into the hackage tarball+ 1.0.0 =====
README.md view
@@ -5,19 +5,15 @@ ## Related work -- [elf](https://github.com/wangbj/elf) - does not write ELF, only parses it-- [data-elf](https://github.com/mvv/data-elf) - parses just headers/tables; depends on a library that fails to build with modern GHCs+- [elf](https://github.com/wangbj/elf)+- [data-elf](https://github.com/mvv/data-elf) +These just parse/serialize ELF header and table entries but not the whole ELF files.+ ## History For the early history look at the branch "[amakarov](https://github.com/aleksey-makarov/elf/tree/amakarov)" of the my copy of the [elf](https://github.com/aleksey-makarov/elf) repo.--## How to build--- [Install](https://nixos.org/manual/nix/stable/#chap-installation) Nix-- `nix-shell`-- `cabal new-configure; cabal new-build` ## Tests
+ examples/AsmAArch64.hs view
@@ -0,0 +1,326 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE StandaloneKindSignatures #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE TypeFamilies #-}++{-# OPTIONS_GHC -Wno-unused-top-binds #-}++module AsmAArch64+ ( CodeState+ , Register+ , RelativeRef+ , adr+ , b+ , mov+ , ldr+ , svc+ , ascii+ , label+ , exportSymbol+ , assemble+ , x0, x1, x2, x8+ , w0, w1+ ) where++import Prelude as P++import Control.Exception.ChainedException+import Control.Monad.Catch+import Control.Monad.State as MS+import Data.Bits+import Data.ByteString.Builder+import Data.ByteString.Lazy as BSL+import Data.ByteString.Lazy.Char8 as BSLC+import Data.Int+import Data.Kind+import Data.Singletons.Sigma+import Data.Singletons.TH+import Data.Word++import Data.Elf+import Data.Elf.Constants+import Data.Elf.Headers++$(singletons [d| data RegisterWidth = X | W |])++type Register :: RegisterWidth -> Type+newtype Register c = R Word32++newtype CodeOffset = CodeOffset { getCodeOffset :: Int64 } deriving (Eq, Show, Ord, Num, Enum, Real, Integral, Bits, FiniteBits)+newtype Instruction = Instruction { getInstruction :: Word32 } deriving (Eq, Show, Ord, Num, Enum, Real, Integral, Bits, FiniteBits)++data RelativeRef = CodeRef !CodeOffset+ | PoolRef !CodeOffset++-- Args:+-- Offset of the instruction+-- Offset of the pool+type InstructionGen = CodeOffset -> CodeOffset -> Either String Instruction++data CodeState = CodeState+ { offsetInPool :: CodeOffset+ , poolReversed :: [Builder]+ , codeReversed :: [InstructionGen]+ , symbolsRefersed :: [(String, RelativeRef)]+ }++emit' :: MonadState CodeState m => InstructionGen -> m ()+emit' g = modify f where+ f CodeState {..} = CodeState { codeReversed = g : codeReversed+ , ..+ }++emit :: MonadState CodeState m => Instruction -> m ()+emit i = emit' $ \ _ _ -> Right i++emitPool :: MonadState CodeState m => Word -> ByteString -> m RelativeRef+emitPool a bs = state f where+ f CodeState {..} =+ let+ offsetInPool' = align a offsetInPool+ o = builderRepeatZero $ fromIntegral $ offsetInPool' - offsetInPool+ in+ ( PoolRef offsetInPool'+ , CodeState { offsetInPool = fromIntegral (BSL.length bs) + offsetInPool'+ , poolReversed = lazyByteString bs : o : poolReversed+ , ..+ }+ )++label :: MonadState CodeState m => m RelativeRef+label = gets (CodeRef . (* instructionSize) . fromIntegral . P.length . codeReversed)++x0, x1, x2, x8 :: Register 'X+x0 = R 0+x1 = R 1+x2 = R 2+x8 = R 8++w0, w1 :: Register 'W+w0 = R 0+w1 = R 1++isPower2 :: (Bits i, Num i) => i -> Bool+isPower2 n = n .&. (n - 1) == 0++align :: Word -> CodeOffset -> CodeOffset+align a _ | not (isPower2 a) = error "align is not a power of 2"+align 0 n = n+align a n = (n + a' - 1) .&. complement (a' - 1)+ where a' = fromIntegral a++builderRepeatZero :: Int -> Builder+builderRepeatZero n = mconcat $ P.replicate n (word8 0)++b64 :: forall w . SingI w => Register w -> Word32+b64 _ = case sing @ w of+ SX -> 1+ SW -> 0++-- | C6.2.10 ADR+adr :: MonadState CodeState m => Register 'X -> RelativeRef -> m ()+adr (R n) rr = emit' f where++ offsetToImm :: CodeOffset -> Either String Word32+ offsetToImm (CodeOffset o) =+ if not $ isBitN 19 o+ then Left "offset is too big"+ else+ let+ immlo = o .&. 3+ immhi = (o `shiftR` 2) .&. 0x7ffff+ in+ Right $ fromIntegral $ (immhi `shift` 5) .|. (immlo `shift` 29)++ f :: InstructionGen+ f instrAddr poolOffset = do+ imm <- offsetToImm $ findOffset poolOffset rr - instrAddr+ return $ Instruction $ 0x10000000+ .|. imm+ .|. n++-- | C6.2.26 B+b :: MonadState CodeState m => RelativeRef -> m ()+b rr = emit' f where++ offsetToImm26 :: CodeOffset -> Either String Word32+ offsetToImm26 (CodeOffset o)+ | o .&. 0x3 /= 0 = Left $ "offset is not aligned: " ++ show o+ | not $ isBitN 28 o = Left "offset is too big"+ | otherwise = Right $ fromIntegral $ o `shiftR` 2++ f :: InstructionGen+ f instrAddr poolOffset = do+ imm26 <- offsetToImm26 $ findOffset poolOffset rr - instrAddr+ return $ Instruction $ 0x14000000 .|. imm26++-- | C6.2.187 MOV (wide immediate)+mov :: (MonadState CodeState m, SingI w) => Register w -> Word16 -> m ()+mov r@(R n) imm = emit $ Instruction $ (b64 r `shift` 31)+ .|. 0x52800000+ .|. (fromIntegral imm `shift` 5)+ .|. n++-- | The number can be represented with bitN bits+isBitN ::(Num b, Bits b, Ord b) => Int -> b -> Bool+isBitN bitN w =+ let+ m = complement $ (1 `shift` bitN) - 1+ h = w .&. m+ in if w >= 0 then h == 0 else h == m++findOffset :: CodeOffset -> RelativeRef -> CodeOffset+findOffset _poolOffset (CodeRef codeOffset) = codeOffset+findOffset poolOffset (PoolRef offsetInPool) = poolOffset + offsetInPool++-- | C6.2.132 LDR (literal)+ldr :: (MonadState CodeState m, SingI w) => Register w -> RelativeRef -> m ()+ldr r@(R n) rr = emit' f where++ offsetToImm19 :: CodeOffset -> Either String Word32+ offsetToImm19 (CodeOffset o)+ | o .&. 0x3 /= 0 = Left "offset is not aligned"+ | not $ isBitN 21 o = Left "offset is too big"+ | otherwise = Right $ fromIntegral $ o `shiftR` 2++ f :: InstructionGen+ f instrAddr poolOffset = do+ imm19 <- offsetToImm19 $ findOffset poolOffset rr - instrAddr+ return $ Instruction $ (b64 r `shift` 30)+ .|. 0x18000000+ .|. (imm19 `shift` 5)+ .|. n++-- | C6.2.317 SVC+svc :: MonadState CodeState m => Word16 -> m ()+svc imm = emit $ 0xd4000001 .|. (fromIntegral imm `shift` 5)++ascii :: MonadState CodeState m => String -> m RelativeRef+ascii s = emitPool 1 $ BSLC.pack s++exportSymbol :: MonadState CodeState m => String -> RelativeRef -> m ()+exportSymbol s r = modify f where+ f (CodeState {..}) = CodeState { symbolsRefersed = (s, r) : symbolsRefersed+ , ..+ }++instructionSize :: Num b => b+instructionSize = 4++zeroIndexStringItem :: ElfSymbolXX 'ELFCLASS64+zeroIndexStringItem = ElfSymbolXX "" 0 0 0 0 0++textSecN, shstrtabSecN, strtabSecN, symtabSecN :: ElfSectionIndex+textSecN = 1+shstrtabSecN = 2+strtabSecN = 3+symtabSecN = 4++assemble :: MonadCatch m => StateT CodeState m () -> m Elf+assemble m = do++ CodeState {..} <- execStateT m (CodeState 0 [] [] [])++ -- resolve txt++ let+ poolOffset = instructionSize * fromIntegral (P.length codeReversed)+ poolOffsetAligned = align 8 poolOffset++ f :: (InstructionGen, CodeOffset) -> Either String Instruction+ f (ff, n) = ff n poolOffsetAligned++ code <- $eitherAddContext' $ mapM f $ P.zip (P.reverse codeReversed) (fmap (instructionSize *) [CodeOffset 0 .. ])++ let+ codeBuilder = mconcat $ fmap (word32LE . getInstruction) code+ txt = toLazyByteString $ codeBuilder+ <> builderRepeatZero (fromIntegral $ poolOffsetAligned - poolOffset)+ <> mconcat (P.reverse poolReversed)++ -- resolve symbolTable++ let+ ff :: (String, RelativeRef) -> ElfSymbolXX 'ELFCLASS64+ ff (s, r) =+ let+ steName = s+ steBind = STB_Global+ steType = STT_NoType+ steShNdx = textSecN+ steValue = fromIntegral $ findOffset poolOffset r+ steSize = 0+ in+ ElfSymbolXX{..}++ symbolTable = ff <$> P.reverse symbolsRefersed++ (symbolTableData, stringTableData) <- serializeSymbolTable ELFDATA2LSB (zeroIndexStringItem : symbolTable)++ return $ SELFCLASS64 :&: ElfList+ [ ElfHeader+ { ehData = ELFDATA2LSB+ , ehOSABI = ELFOSABI_SYSV+ , ehABIVersion = 0+ , ehType = ET_REL+ , ehMachine = EM_AARCH64+ , ehEntry = 0+ , ehFlags = 0+ }+ , ElfSection+ { esName = ".text"+ , esType = SHT_PROGBITS+ , esFlags = SHF_EXECINSTR .|. SHF_ALLOC+ , esAddr = 0+ , esAddrAlign = 8+ , esEntSize = 0+ , esN = textSecN+ , esLink = 0+ , esInfo = 0+ , esData = ElfSectionData txt+ }+ , ElfSection+ { esName = ".shstrtab"+ , esType = SHT_STRTAB+ , esFlags = 0+ , esAddr = 0+ , esAddrAlign = 1+ , esEntSize = 0+ , esN = shstrtabSecN+ , esLink = 0+ , esInfo = 0+ , esData = ElfSectionDataStringTable+ }+ , ElfSection+ { esName = ".symtab"+ , esType = SHT_SYMTAB+ , esFlags = 0+ , esAddr = 0+ , esAddrAlign = 8+ , esEntSize = symbolTableEntrySize ELFCLASS64+ , esN = symtabSecN+ , esLink = fromIntegral strtabSecN+ , esInfo = 1+ , esData = ElfSectionData symbolTableData+ }+ , ElfSection+ { esName = ".strtab"+ , esType = SHT_STRTAB+ , esFlags = 0+ , esAddr = 0+ , esAddrAlign = 1+ , esEntSize = 0+ , esN = strtabSecN+ , esLink = 0+ , esInfo = 0+ , esData = ElfSectionData stringTableData+ }+ , ElfSectionTable+ ]
− examples/AsmAarch64.hs
@@ -1,258 +0,0 @@-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE StandaloneKindSignatures #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeApplications #-}-{-# LANGUAGE TypeFamilies #-}--{-# OPTIONS_GHC -Wno-unused-top-binds #-}--module AsmAarch64- ( CodeState- , Register- , RelativeRef- , adr- , b- , mov- , ldr- , svc- , ascii- , label- , exportSymbol- , assemble- , x0, x1, x2, x8- , w0, w1- ) where--import Prelude as P--import Control.Exception.ChainedException-import Control.Monad.Catch-import Control.Monad.State as MS-import Data.Bits-import Data.ByteString.Builder-import Data.ByteString.Lazy as BSL-import Data.ByteString.Lazy.Char8 as BSLC-import Data.Int-import Data.Kind-import Data.Singletons.TH-import Data.Word--import Data.Elf-import Data.Elf.Constants-import Data.Elf.Headers--$(singletons [d| data RegisterWidth = X | W |])--type Register :: RegisterWidth -> Type-newtype Register c = R Word32--newtype CodeOffset = CodeOffset { getCodeOffset :: Int64 } deriving (Eq, Show, Ord, Num, Enum, Real, Integral, Bits, FiniteBits)-newtype Instruction = Instruction { getInstruction :: Word32 } deriving (Eq, Show, Ord, Num, Enum, Real, Integral, Bits, FiniteBits)--data RelativeRef = CodeRef !CodeOffset- | PoolRef !CodeOffset---- Args:--- Offset of the instruction--- Offset of the pool-type InstructionGen = CodeOffset -> CodeOffset -> Either String Instruction--data CodeState = CodeState- { offsetInPool :: CodeOffset- , poolReversed :: [Builder]- , codeReversed :: [InstructionGen]- , symbolsRefersed :: [(String, RelativeRef)]- }--emit' :: MonadState CodeState m => InstructionGen -> m ()-emit' g = modify f where- f CodeState {..} = CodeState { codeReversed = g : codeReversed- , ..- }--emit :: MonadState CodeState m => Instruction -> m ()-emit i = emit' $ \ _ _ -> Right i--emitPool :: MonadState CodeState m => Word -> ByteString -> m RelativeRef-emitPool a bs = state f where- f CodeState {..} =- let- offsetInPool' = align a offsetInPool- o = builderRepeatZero $ fromIntegral $ offsetInPool' - offsetInPool- in- ( PoolRef offsetInPool'- , CodeState { offsetInPool = fromIntegral (BSL.length bs) + offsetInPool'- , poolReversed = lazyByteString bs : o : poolReversed- , ..- }- )--label :: MonadState CodeState m => m RelativeRef-label = gets (CodeRef . (* instructionSize) . fromIntegral . P.length . codeReversed)--x0, x1, x2, x8 :: Register 'X-x0 = R 0-x1 = R 1-x2 = R 2-x8 = R 8--w0, w1 :: Register 'W-w0 = R 0-w1 = R 1--isPower2 :: (Bits i, Num i) => i -> Bool-isPower2 n = n .&. (n - 1) == 0--align :: Word -> CodeOffset -> CodeOffset-align a _ | not (isPower2 a) = error "align is not a power of 2"-align 0 n = n-align a n = (n + a' - 1) .&. complement (a' - 1)- where a' = fromIntegral a--builderRepeatZero :: Int -> Builder-builderRepeatZero n = mconcat $ P.replicate n (word8 0)--b64 :: forall w . SingI w => Register w -> Word32-b64 _ = case sing @ w of- SX -> 1- SW -> 0---- | C6.2.10 ADR-adr :: MonadState CodeState m => Register 'X -> RelativeRef -> m ()-adr (R n) rr = emit' f where-- offsetToImm :: CodeOffset -> Either String Word32- offsetToImm (CodeOffset o) =- if not $ isBitN 19 o- then Left "offset is too big"- else- let- immlo = o .&. 3- immhi = (o `shiftR` 2) .&. 0x7ffff- in- Right $ fromIntegral $ (immhi `shift` 5) .|. (immlo `shift` 29)-- f :: InstructionGen- f instrAddr poolOffset = do- imm <- offsetToImm $ findOffset poolOffset rr - instrAddr- return $ Instruction $ 0x10000000- .|. imm- .|. n---- | C6.2.26 B-b :: MonadState CodeState m => RelativeRef -> m ()-b rr = emit' f where-- offsetToImm26 :: CodeOffset -> Either String Word32- offsetToImm26 (CodeOffset o)- | o .&. 0x3 /= 0 = Left $ "offset is not aligned: " ++ show o- | not $ isBitN 28 o = Left "offset is too big"- | otherwise = Right $ fromIntegral $ o `shiftR` 2-- f :: InstructionGen- f instrAddr poolOffset = do- imm26 <- offsetToImm26 $ findOffset poolOffset rr - instrAddr- return $ Instruction $ 0x14000000 .|. imm26---- | C6.2.187 MOV (wide immediate)-mov :: (MonadState CodeState m, SingI w) => Register w -> Word16 -> m ()-mov r@(R n) imm = emit $ Instruction $ (b64 r `shift` 31)- .|. 0x52800000- .|. (fromIntegral imm `shift` 5)- .|. n---- | The number can be represented with bitN bits-isBitN ::(Num b, Bits b, Ord b) => Int -> b -> Bool-isBitN bitN w =- let- m = complement $ (1 `shift` bitN) - 1- h = w .&. m- in if w >= 0 then h == 0 else h == m--findOffset :: CodeOffset -> RelativeRef -> CodeOffset-findOffset _poolOffset (CodeRef codeOffset) = codeOffset-findOffset poolOffset (PoolRef offsetInPool) = poolOffset + offsetInPool---- | C6.2.132 LDR (literal)-ldr :: (MonadState CodeState m, SingI w) => Register w -> RelativeRef -> m ()-ldr r@(R n) rr = emit' f where-- offsetToImm19 :: CodeOffset -> Either String Word32- offsetToImm19 (CodeOffset o)- | o .&. 0x3 /= 0 = Left "offset is not aligned"- | not $ isBitN 21 o = Left "offset is too big"- | otherwise = Right $ fromIntegral $ o `shiftR` 2-- f :: InstructionGen- f instrAddr poolOffset = do- imm19 <- offsetToImm19 $ findOffset poolOffset rr - instrAddr- return $ Instruction $ (b64 r `shift` 30)- .|. 0x18000000- .|. (imm19 `shift` 5)- .|. n---- | C6.2.317 SVC-svc :: MonadState CodeState m => Word16 -> m ()-svc imm = emit $ 0xd4000001 .|. (fromIntegral imm `shift` 5)--ascii :: MonadState CodeState m => String -> m RelativeRef-ascii s = emitPool 1 $ BSLC.pack s--exportSymbol :: MonadState CodeState m => String -> RelativeRef -> m ()-exportSymbol s r = modify f where- f (CodeState {..}) = CodeState { symbolsRefersed = (s, r) : symbolsRefersed- , ..- }--instructionSize :: Num b => b-instructionSize = 4--zeroIndexStringItem :: ElfSymbolXX 'ELFCLASS64-zeroIndexStringItem = ElfSymbolXX "" 0 0 0 0 0--assemble :: MonadCatch m => ElfSectionIndex -> StateT CodeState m () -> m (BSL.ByteString, [ElfSymbolXX 'ELFCLASS64])-assemble textSecN m = do-- CodeState {..} <- execStateT m (CodeState 0 [] [] [])-- -- resolve txt-- let- poolOffset = instructionSize * fromIntegral (P.length codeReversed)- poolOffsetAligned = align 8 poolOffset-- f :: (InstructionGen, CodeOffset) -> Either String Instruction- f (ff, n) = ff n poolOffsetAligned-- code <- $eitherAddContext' $ mapM f $ P.zip (P.reverse codeReversed) (fmap (instructionSize *) [CodeOffset 0 .. ])-- let- codeBuilder = mconcat $ fmap (word32LE . getInstruction) code- txt = toLazyByteString $ codeBuilder- <> builderRepeatZero (fromIntegral $ poolOffsetAligned - poolOffset)- <> mconcat (P.reverse poolReversed)-- -- resolve symbolTable-- let- ff :: (String, RelativeRef) -> ElfSymbolXX 'ELFCLASS64- ff (s, r) =- let- steName = s- steBind = STB_Global- steType = STT_NoType- steShNdx = textSecN- steValue = fromIntegral $ findOffset poolOffset r- steSize = 0- in- ElfSymbolXX{..}-- symbolTable = ff <$> P.reverse symbolsRefersed-- return (txt, zeroIndexStringItem : symbolTable)
+ examples/DummyLd.hs view
@@ -0,0 +1,63 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}++module DummyLd (dummyLd) where++import Control.Monad.Catch+import Data.Bits+import Data.ByteString.Lazy as BSL+import Data.Word+import Data.Singletons.Sigma++import Data.Elf+import Data.Elf.Constants+import Data.Elf.Headers+import Control.Exception.ChainedException++addr :: Word64+addr = 0x400000++mkExe :: MonadThrow m => BSL.ByteString -> m (ElfList 'ELFCLASS64)+mkExe txt = return $ ElfList [ segment ]+ where+ segment = ElfSegment+ { epType = PT_LOAD+ , epFlags = PF_X .|. PF_R+ , epVirtAddr = addr+ , epPhysAddr = addr+ , epAddMemSize = 0+ , epAlign = 0x10000+ , epData =+ [ ElfHeader+ { ehData = ELFDATA2LSB+ , ehOSABI = ELFOSABI_SYSV+ , ehABIVersion = 0+ , ehType = ET_EXEC+ , ehMachine = EM_AARCH64+ , ehEntry = addr + headerSize ELFCLASS64+ , ehFlags = 0+ }+ , ElfRawData+ { edData = txt+ }+ , ElfSegmentTable+ ]+ }++dummyLd' :: MonadThrow m => ElfList 'ELFCLASS64 -> m (ElfList 'ELFCLASS64)+dummyLd' (ElfList es) = do++ txtSection <- elfFindSectionByName es ".text"++ case txtSection of+ ElfSection{esData = ElfSectionData textData} -> mkExe textData+ _ -> $chainedError "could not find correct \".text\" section"++-- | It places the content of ".text" section of the input ELF into the+-- loadable segment of the resulting ELF.+-- It could work if there are no relocations or references to external symbols+dummyLd :: MonadThrow m => Elf -> m Elf+dummyLd (SELFCLASS32 :&: _) = $chainedError "AArch64 arch object expected"+dummyLd (SELFCLASS64 :&: es) = (SELFCLASS64 :&:) <$> dummyLd' es
examples/Examples.hs view
@@ -13,8 +13,8 @@ import Data.Elf import Data.Elf.PrettyPrint -import MkObj-import MkExe+import DummyLd+import AsmAArch64 import HelloWorld import ForwardLabel @@ -24,13 +24,13 @@ setFileMode path $ m .|. ownerExecuteMode helloWorldExe :: MonadCatch m => m Elf-helloWorldExe = mkExe helloWorld+helloWorldExe = assemble helloWorld >>= dummyLd forwardLabelExe :: (MonadCatch m, MonadFix m) => m Elf-forwardLabelExe = mkExe forwardLabel+forwardLabelExe = assemble forwardLabel >>= dummyLd helloWorldObj :: MonadCatch m => m Elf-helloWorldObj = mkObj helloWorld+helloWorldObj = assemble helloWorld fixTargetName :: String -> String fixTargetName = fmap f
examples/ForwardLabel.hs view
@@ -9,7 +9,7 @@ import Control.Monad.Fix import Control.Monad.State -import AsmAarch64+import AsmAArch64 ok :: String ok = "ok\n"
examples/HelloWorld.hs view
@@ -8,7 +8,7 @@ import Control.Monad.State import Data.Word -import AsmAarch64+import AsmAArch64 msg :: String msg = "Hello World!\n"
− examples/MkExe.hs
@@ -1,45 +0,0 @@-module MkExe (mkExe) where--import Control.Monad.Catch-import Control.Monad.State-import Data.Bits-import Data.Word-import Data.Singletons.Sigma--import Data.Elf-import Data.Elf.Constants-import Data.Elf.Headers--import AsmAarch64--addr :: Word64-addr = 0x400000--mkExe :: MonadCatch m => StateT CodeState m () -> m Elf-mkExe m = do- (txt, _) <- assemble 1 m- let- segment = ElfSegment- { epType = PT_LOAD- , epFlags = PF_X .|. PF_R- , epVirtAddr = addr- , epPhysAddr = addr- , epAddMemSize = 0- , epAlign = 0x10000- , epData =- [ ElfHeader- { ehData = ELFDATA2LSB- , ehOSABI = ELFOSABI_SYSV- , ehABIVersion = 0- , ehType = ET_EXEC- , ehMachine = EM_AARCH64- , ehEntry = addr + headerSize ELFCLASS64- , ehFlags = 0- }- , ElfRawData- { edData = txt- }- , ElfSegmentTable- ]- }- return $ SELFCLASS64 :&: ElfList [ segment ]
− examples/MkObj.hs
@@ -1,89 +0,0 @@-{-# LANGUAGE DataKinds #-}--module MkObj (mkObj) where--import Prelude as P--import Control.Monad.Catch-import Control.Monad.State-import Data.Bits-import Data.Singletons.Sigma--import Data.Elf-import Data.Elf.Constants-import Data.Elf.Headers--import AsmAarch64--textSecN, shstrtabSecN, strtabSecN, symtabSecN :: ElfSectionIndex-textSecN = 1-shstrtabSecN = 2-strtabSecN = 3-symtabSecN = 4--mkObj :: MonadCatch m => StateT CodeState m () -> m Elf-mkObj m = do-- (txt, symbolTable) <- assemble textSecN m- (symbolTableData, stringTableData) <- serializeSymbolTable ELFDATA2LSB symbolTable-- return $ SELFCLASS64 :&: ElfList- [ ElfHeader- { ehData = ELFDATA2LSB- , ehOSABI = ELFOSABI_SYSV- , ehABIVersion = 0- , ehType = ET_REL- , ehMachine = EM_AARCH64- , ehEntry = 0- , ehFlags = 0- }- , ElfSection- { esName = ".text"- , esType = SHT_PROGBITS- , esFlags = SHF_EXECINSTR .|. SHF_ALLOC- , esAddr = 0- , esAddrAlign = 8- , esEntSize = 0- , esN = textSecN- , esLink = 0- , esInfo = 0- , esData = ElfSectionData txt- }- , ElfSection- { esName = ".shstrtab"- , esType = SHT_STRTAB- , esFlags = 0- , esAddr = 0- , esAddrAlign = 1- , esEntSize = 0- , esN = shstrtabSecN- , esLink = 0- , esInfo = 0- , esData = ElfSectionDataStringTable- }- , ElfSection- { esName = ".symtab"- , esType = SHT_SYMTAB- , esFlags = 0- , esAddr = 0- , esAddrAlign = 8- , esEntSize = symbolTableEntrySize ELFCLASS64- , esN = symtabSecN- , esLink = fromIntegral strtabSecN- , esInfo = 1- , esData = ElfSectionData symbolTableData- }- , ElfSection- { esName = ".strtab"- , esType = SHT_STRTAB- , esFlags = 0- , esAddr = 0- , esAddrAlign = 1- , esEntSize = 0- , esN = strtabSecN- , esLink = 0- , esInfo = 0- , esData = ElfSectionData stringTableData- }- , ElfSectionTable- ]
+ examples/README_ru.md view
@@ -0,0 +1,706 @@+---+title: Работа с файлами формата ELF из Хаскела+date: November 17, 2021+---++Работа с файлами формата ELF -- популярная тема на Хабре.+(["Введение в ELF-файлы в Linux: понимание и анализ"](https://habr.com/ru/post/480642/),+["Минимизация файла ELF – попробуем в 2021?"](https://habr.com/ru/company/ruvds/blog/583576/) и т. д.)++Существуют библиотеки для Хаскела для работы с этими файлами: `elf`+([Hackage](https://hackage.haskell.org/package/elf)) и `data-elf`+([Hackage](https://hackage.haskell.org/package/data-elf)).+Эти библиотеки работают только с заголовками и элементами таблиц и не дают возможности+сгенерировать объектный файл.++Я написал библиотеку для работы с файлами формата ELF на Хаскеле+([GitHub](https://github.com/aleksey-makarov/melf),+ [Hackage](https://hackage.haskell.org/package/melf))+и хочу показать как её использовать.++## Внутреннее устройство ELF++Первые несколько байт файла занимает заголовок ELF.+В нём, в частности, указано, где в файле расположены таблица секций и таблица сегментов.++Сегменты и секции -- непрерывные участки файла.+Сегменты описывают, что нужно поместить в память при загрузки программы,+а секции я бы описал как неделимые результаты работы+компилятора.+В секциях размещены исполняемый код, таблицы символов, инициализированные данные.++Файл формата ELF можно представлять как список деревьев.+Деревьями могуть быть секции, сегменты, заголовок файла, таблица секций, таблица сегментов.+Поддеревья могут содержаться только в сегментах.+Узлы дерева выравниваются в файле, например, сегменты обычно выравниваются на размер страницы,+а секции с данными -- на размер слова.+Вполне валидным может быть файл, где сегмент содержит данные, не размеченные как какая-либо секция.++## Базовый уровень++В модуле+[`Data.Elf.Headers`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html)+реализованы разбор и сериализация заголовка файла ELF и+элементов таблиц секций и сегментов. Для различения 64- и 32-битных структур +определён тип+[`ElfClass`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:ElfClass)++``` Haskell+data ElfClass+ = ELFCLASS32 -- ^ 32-bit ELF format+ | ELFCLASS64 -- ^ 64-bit ELF format+ deriving (Eq, Show)+```++Некоторые поля заголовка и элементов таблиц секций и сегментов имеют разную ширину в битах, зависящую от+`ElfClass`, поэтому нужен тип+[`WordXX a`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:WordXX),+который был позаимствован из пакета `data-elf`:++``` Haskell+-- | @IsElfClass a@ is defined for each constructor of `ElfClass`.+-- It defines @WordXX a@, which is `Word32` for `ELFCLASS32`+-- and `Word64` for `ELFCLASS64`.+type IsElfClass :: ElfClass -> Constraint+class ( SingI c+ , Typeable c+ , Typeable (WordXX c)+ , Data (WordXX c)+ , Show (WordXX c)+ , Read (WordXX c)+ , Eq (WordXX c)+ , Ord (WordXX c)+ , Bounded (WordXX c)+ , Enum (WordXX c)+ , Num (WordXX c)+ , Integral (WordXX c)+ , Real (WordXX c)+ , Bits (WordXX c)+ , FiniteBits (WordXX c)+ , Binary (Be (WordXX c))+ , Binary (Le (WordXX c))+ ) => IsElfClass c where+ type WordXX c = r | r -> c++instance IsElfClass 'ELFCLASS32 where+ type WordXX 'ELFCLASS32 = Word32++instance IsElfClass 'ELFCLASS64 where+ type WordXX 'ELFCLASS64 = Word64+```++Заголовок файла ELF представлен с помощью типа+[`HeaderXX a`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:HeaderXX):++``` Haskell+-- | Parsed ELF header+type HeaderXX :: ElfClass -> Type+data HeaderXX c =+ HeaderXX+ { hData :: ElfData -- ^ Data encoding (big- or little-endian)+ , hOSABI :: ElfOSABI -- ^ OS/ABI identification+ , hABIVersion :: Word8 -- ^ ABI version+ , hType :: ElfType -- ^ Object file type+ , hMachine :: ElfMachine -- ^ Machine type+ , hEntry :: WordXX c -- ^ Entry point address+ , hPhOff :: WordXX c -- ^ Program header offset+ , hShOff :: WordXX c -- ^ Section header offset+ , hFlags :: Word32 -- ^ Processor-specific flags+ , hPhEntSize :: Word16 -- ^ Size of program header entry+ , hPhNum :: Word16 -- ^ Number of program header entries+ , hShEntSize :: Word16 -- ^ Size of section header entry+ , hShNum :: Word16 -- ^ Number of section header entries+ , hShStrNdx :: ElfSectionIndex -- ^ Section name string table index+ }+```++Но это разные типы для 64- и 32-битных форматов.+Для однообразной работы с форматами с разной шириной слова определён тип+[`Header`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:Header):++``` Haskell+-- | Sigma type where `ElfClass` defines the type of `HeaderXX`+type Header = Sigma ElfClass (TyCon1 HeaderXX)+```++`Header` это пара, первый элемент которой -- объект типа `ElfClass`, определяющий ширину слова,+второй -- `HeaderXX`, параметризованный первым элементом ($\Sigma$-тип из языков с зависимыми типами).+Для симуляции $\Sigma$-типов использована библиотека `singletons`+([Hackage](https://hackage.haskell.org/package/singletons),+ ["Introduction to singletons"](https://blog.jle.im/entry/introduction-to-singletons-1.html)).++Для `Header` определён экземпляр класса+[`Binary`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary.html#t:Binary).++Таким образом, имея ленивую строку байт, содержащую достаточно длинный начальный отрезок файла ELF,+можно получить заголовок этого файла, например, следующей функцией:++``` Haskell+withHeader :: BSL.ByteString ->+ (forall a . IsElfClass a => HeaderXX a -> b) -> Either String b+withHeader bs f =+ case decodeOrFail bs of+ Left (_, _, err) -> Left err+ Right (_, _, (classS :&: hxx) :: Header) ->+ Right $ withElfClass classS f hxx+```++Здесь+[`decodeOrFail`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary.html#v:decodeOrFail) определена в пакете+[`binary`](https://hackage.haskell.org/package/binary), а+[`withElfClass`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#v:withElfClass)+похожа на+[`withSing`](https://hackage.haskell.org/package/singletons-3.0.1/docs/Data-Singletons.html#v:withSing):++``` Haskell+-- | Convenience function for creating a+-- context with an implicit ElfClass available.+withElfClass :: Sing c -> (IsElfClass c => a) -> a+withElfClass SELFCLASS64 x = x+withElfClass SELFCLASS32 x = x+```++В `Data.Elf.Headers` определены также типы+[`SectionXX`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:SectionXX),+[`SegmentXX`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:SegmentXX) и+[`SymbolXX`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:SymbolXX)+для элементов таблиц секций, сегментов и символов.++## Верхний уровень++В модуле+[`Data.Elf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html)+реализованы полные разбор и сериализация файлов формата ELF.+Чтобы разобрать такой файл читаются заголовок ELF, таблицa секций и таблица сегментов и+на основании этой информации создаётся список элементов типа+[`ElfXX`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#t:ElfXX),+отображающий рекурсивную+структуру файла ELF. Кроме восстановления структуры в процессе разбора, например, по номерам+секций восстанавливаются их имена. В результате получается объект типа+[`Elf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#t:Elf):++``` Haskell+-- | `Elf` is a forrest of trees of type `ElfXX`.+-- Trees are composed of `ElfXX` nodes, `ElfSegment` can contain subtrees+newtype ElfList c = ElfList [ElfXX c]++-- | Elf is a sigma type where `ElfClass` defines the type of `ElfList`+type Elf = Sigma ElfClass (TyCon1 ElfList)++-- | Section data may contain a string table.+-- If a section contains a string table with section names, the data+-- for such a section is generated and `esData` should contain `ElfSectionDataStringTable`+data ElfSectionData+ = ElfSectionData BSL.ByteString -- ^ Regular section data+ | ElfSectionDataStringTable -- ^ Section data will be generated from section names++-- | The type of node that defines Elf structure.+data ElfXX (c :: ElfClass)+ = ElfHeader+ { ehData :: ElfData -- ^ Data encoding (big- or little-endian)+ , ehOSABI :: ElfOSABI -- ^ OS/ABI identification+ , ehABIVersion :: Word8 -- ^ ABI version+ , ehType :: ElfType -- ^ Object file type+ , ehMachine :: ElfMachine -- ^ Machine type+ , ehEntry :: WordXX c -- ^ Entry point address+ , ehFlags :: Word32 -- ^ Processor-specific flags+ }+ | ElfSectionTable+ | ElfSegmentTable+ | ElfSection+ { esName :: String -- ^ Section name (NB: string, not offset in the string table)+ , esType :: ElfSectionType -- ^ Section type+ , esFlags :: ElfSectionFlag -- ^ Section attributes+ , esAddr :: WordXX c -- ^ Virtual address in memory+ , esAddrAlign :: WordXX c -- ^ Address alignment boundary+ , esEntSize :: WordXX c -- ^ Size of entries, if section has table+ , esN :: ElfSectionIndex -- ^ Section number+ , esInfo :: Word32 -- ^ Miscellaneous information+ , esLink :: Word32 -- ^ Link to other section+ , esData :: ElfSectionData -- ^ The content of the section+ }+ | ElfSegment+ { epType :: ElfSegmentType -- ^ Type of segment+ , epFlags :: ElfSegmentFlag -- ^ Segment attributes+ , epVirtAddr :: WordXX c -- ^ Virtual address in memory+ , epPhysAddr :: WordXX c -- ^ Physical address+ , epAddMemSize :: WordXX c -- ^ Add this amount of memory after the section when the section is loaded to memory by execution system.+ -- Or, in other words this is how much `pMemSize` is bigger than `pFileSize`+ , epAlign :: WordXX c -- ^ Alignment of segment+ , epData :: [ElfXX c] -- ^ Content of the segment+ }+ | ElfRawData -- ^ Some ELF files (some executables) don't bother to define+ -- sections for linking and have just raw data in segments.+ { edData :: BSL.ByteString -- ^ Raw data in ELF file+ }+ | ElfRawAlign -- ^ Align the next data in the ELF file.+ -- The offset of the next data in the ELF file+ -- will be the minimal @x@ such that+ -- @x mod eaAlign == eaOffset mod eaAlign @+ { eaOffset :: WordXX c -- ^ Align value+ , eaAlign :: WordXX c -- ^ Align module+ }++```++Не каждый объект такого типа может быть сериализован.++ * В конструкторе `ElfSection`+остался номер секции. Он нужен, так как таблица символов и некоторые другие структуры+ссылаются на секци по их номерам. Поэтому при построении объекта такого типа нужно убедиться,+что секции пронумерованы корректно, т. е. последовательными целыми от 1 до количества секций.+Секция с номером 0 всегда пустая и она добавляется автоматически.++ * В структуре должен быть единственный `ElfHeader`, он должен быть самым первым непустым+ узлом в дереве.++ * Если есть хотя бы один узел `ElfSection`, то должен присутсвовать в точности один узел `ElfSectionTable`+ и в точности одна секция, поле `esData` которой равно `ElfSectionDataStringTable` (таблица строк для имён секций).++ * Если есть хотя бы один узел с конструктором `ElfSegment`, то должен присутсвовать в точности один узел `ElfSegmentTable`.++Корректно сформированный объект можно сериализовать с помощью функции+[`serializeElf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#v:serializeElf)+и разобрать с помощью функции+[`parseElf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#v:parseElf):++``` Haskell+serializeElf :: MonadThrow m => Elf -> m ByteString+parseElf :: MonadCatch m => ByteString -> m Elf+```++Экземпляр класса `Binary` для `ELF` не определён, так как+[`Put`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary.html#t:Put)+не является экземпляром класса `MonadFail`.++## Ассемблер как EDSL для Хаскела++Для использования в демонстрационных приложениях написан модуль, +генерирующий машинный код для AArch64+(файл [`AsmAarch64.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/AsmAarch64.hs)).+Сгенерированный код использует системные вызовы чтобы вывести на стандартный вывод "Hello World!" и завершить приложение.+Идея позаимствована из вдохновляющей статьи Стивена Дила "От монад к машинному коду"+([Stephen Diehl "Monads to Machine Code"](https://www.stephendiehl.com/posts/monads_machine_code.html)).+Так же как в статье, используется монада состояния, в нашем случае `CodeState`.++Инициализированные, в частности, константные данные часто размещаются в отдельных секциях.+В нашем случае для константной строки использованы массивы литералов (literal pools).+При этом данные размещаются в той же секции, что и машинный код, в месте,+недоступном потоку исполнения, например, после команды возвращения из подпрограммы.+При этом оказывается легко обращаться к таким данным с помощью команд,+вычисляющих адрес данных с использованием счётчика команд.+Код, обращающийся к таким данным, не требует использования таблицы перемещений.+`CodeState` содержит размер массива литералов, сам массив литералов, массив машинных кодов и массив символов:++``` Haskell+data CodeState = CodeState+ { offsetInPool :: CodeOffset+ , poolReversed :: [Builder]+ , codeReversed :: [InstructionGen]+ , symbolsRefersed :: [(String, RelativeRef)]+ }+```++Для создания меток и ссылок на данные в массиве литералов введён тип `RelativeRef`++``` Haskell+newtype CodeOffset = CodeOffset { getCodeOffset :: Int64 }+ deriving (Eq, Show, Ord, Num, Enum, Real, Integral,+ Bits, FiniteBits)++data RelativeRef = CodeRef CodeOffset+ | PoolRef CodeOffset+```++Конструктор `CodeRef` используется для ссылки на код (для создания меток):++``` Haskell+label :: MonadState CodeState m => m RelativeRef+label = gets (CodeRef . (* instructionSize)+ . fromIntegral+ . P.length+ . codeReversed)+```++Конструктор `PoolRef` хранит смещение данных от начала массива литералов.++Фактически в массиве машинных кодов хранятся функции для генерации машинного кода+из смещения команды от начала секции и смещения массива литералов (которое будет+известно только после обработки всех ассемблерных команд, так как массив литералов+располагается после кода):++```Haskell+type InstructionGen = CodeOffset ->+ CodeOffset -> Either String Instruction+```++Для добавления в массив машинных кодов используется функция `emit'`:++```Haskell+emit' :: MonadState CodeState m => InstructionGen -> m ()+emit' g = modify f where+ f CodeState {..} = CodeState { codeReversed = g : codeReversed+ , ..+ }++emit :: MonadState CodeState m => Instruction -> m ()+emit i = emit' $ \ _ _ -> Right i+```++Каждая встретившаяся ассемблерная команда добавляет в этот массив очередной машинный код,+например:++``` Haskell+-- | C6.2.317 SVC+svc :: MonadState CodeState m => Word16 -> m ()+svc imm = emit $ 0xd4000001 .|. (fromIntegral imm `shift` 5)+```++Как и многие другие команды архитектуры AArch64, команда `mov` может работать с регистрами+как с 64-битными или как с 32-битными значениями.+Для указания разрядности регистров для них используются разные имена:+`x0`, `x1`... -- для 64-битных, `w0`, `w1`... -- для 32-битных.+Регистры определены с помощью [фантомного](https://wiki.haskell.org/Phantom_type) типа:+++``` Haskell+data RegisterWidth = X | W++type Register :: RegisterWidth -> Type+newtype Register c = R Word32++x0, x1 :: Register 'X+x0 = R 0+x1 = R 1++w0, w1 :: Register 'W+w0 = R 0+w1 = R 1++-- | C6.2.187 MOV (wide immediate)+mov :: (MonadState CodeState m, SingI w) =>+ Register w ->+ Word16 -> m ()+```++В системе команд AArch64 есть несколько вариантов команды `mov`.+Реализована только команда с непосредственным широким аргументом (wide immediate).++Команда `adr` работает с регистрами только как с 64-битными значениями:++``` Haskell+-- | C6.2.10 ADR+adr :: MonadState CodeState m =>+ Register 'X ->+ RelativeRef -> m ()+```++Для добавления данных в массив литералов используется функция `emitPool`:++``` Haskell+emitPool :: MonadState CodeState m =>+ Word ->+ ByteString -> m RelativeRef+```++Здесь первый аргумент -- необходимое выравнивание, второй -- данные, которые нужно+разместить в массиве. Функция вычисляет, сколько нужно добавить байт чтобы выравнять+данные, заносит соответствующую нулевую последовательность байт в массив `poolReversed`,+добавляет в этот же массив данные и корректирует `offsetInPool`.++С помощью этой функции можно, например, реализовать аналог ассемблерной директивы `.ascii`:++``` Haskell+ascii :: MonadState CodeState m => String -> m RelativeRef+ascii s = emitPool 1 $ BSLC.pack s+```++Кроме того, есть массив символов. Символы создаются из меток:++``` Haskell+exportSymbol :: MonadState CodeState m => String -> RelativeRef -> m ()+exportSymbol s r = modify f where+ f (CodeState {..}) = CodeState { symbolsRefersed = (s, r) : symbolsRefersed+ , ..+ }+```++Функция `assemble` генерирует код из `CodeState`:++``` Haskell+assemble :: MonadCatch m =>+ ElfSectionIndex ->+ StateT CodeState m () -> m (BSL.ByteString, [ElfSymbolXX 'ELFCLASS64])+```++Первый аргумент -- номер секции, которая будет содержать код,+второй -- программа, которую нужно преобразовать в код.+Функция возвращает пару, первый элемент которой -- содержание+секции ".text", второй -- таблица символов.++Для простоты не реализовано обращение к внешним символам и размещение данных в+отдельных секциях.+Всё это требует реализации таблиц перемещений, с другой стороры, сгенерированный код+получается позиционно-независимым.++Код для вывода "Hello World!" на встроенном в Хаскелл DSL выглядит так+([файл `HelloWordl.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/HelloWorld.hs)):++``` Haskell+{-# LANGUAGE DataKinds #-}++module HelloWorld (helloWorld) where++import Prelude as P++import Control.Monad.Catch+import Control.Monad.State+import Data.Word++import AsmAarch64++msg :: String+msg = "Hello World!\n"++sys_exit, sys_write :: Word16+sys_write = 64+sys_exit = 93++helloWorld :: MonadCatch m => StateT CodeState m ()+helloWorld = do++ start <- label+ exportSymbol "_start" start+ mov x0 1+ helloString <- ascii msg+ adr x1 helloString+ mov x2 $ fromIntegral $ P.length msg+ mov x8 sys_write+ svc 0++ mov x0 0+ mov x8 sys_exit+ svc 0+```+Если нужно сослаться на метку, сформированную ниже по коду, нужно работать в монаде `MonadFix`+и использовать ключевое слово `mdo` вместо `do`+(см. файл [`ForwardLabel.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/ForwardLabel.hs)).++## Генерация объектных файлов++Используем библиотеку `melf` для генерации объектных файлов+([файл `MkObj.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/MkObj.hs)):++``` Haskell+{-# LANGUAGE DataKinds #-}++module MkObj (mkObj) where++import Prelude as P++import Control.Monad.Catch+import Control.Monad.State+import Data.Bits+import Data.Singletons.Sigma++import Data.Elf+import Data.Elf.Constants+import Data.Elf.Headers++import AsmAarch64++textSecN, shstrtabSecN, strtabSecN, symtabSecN :: ElfSectionIndex+textSecN = 1+shstrtabSecN = 2+strtabSecN = 3+symtabSecN = 4++mkObj :: MonadCatch m => StateT CodeState m () -> m Elf+mkObj m = do++ (txt, symbolTable) <- assemble textSecN m+ (symbolTableData, stringTableData) <- serializeSymbolTable ELFDATA2LSB symbolTable++ return $ SELFCLASS64 :&: ElfList+ [ ElfHeader+ { ehData = ELFDATA2LSB+ , ehOSABI = ELFOSABI_SYSV+ , ehABIVersion = 0+ , ehType = ET_REL+ , ehMachine = EM_AARCH64+ , ehEntry = 0+ , ehFlags = 0+ }+ , ElfSection+ { esName = ".text"+ , esType = SHT_PROGBITS+ , esFlags = SHF_EXECINSTR .|. SHF_ALLOC+ , esAddr = 0+ , esAddrAlign = 8+ , esEntSize = 0+ , esN = textSecN+ , esLink = 0+ , esInfo = 0+ , esData = ElfSectionData txt+ }+ , ElfSection+ { esName = ".shstrtab"+ , esType = SHT_STRTAB+ , esFlags = 0+ , esAddr = 0+ , esAddrAlign = 1+ , esEntSize = 0+ , esN = shstrtabSecN+ , esLink = 0+ , esInfo = 0+ , esData = ElfSectionDataStringTable+ }+ , ElfSection+ { esName = ".symtab"+ , esType = SHT_SYMTAB+ , esFlags = 0+ , esAddr = 0+ , esAddrAlign = 8+ , esEntSize = symbolTableEntrySize ELFCLASS64+ , esN = symtabSecN+ , esLink = fromIntegral strtabSecN+ , esInfo = 1+ , esData = ElfSectionData symbolTableData+ }+ , ElfSection+ { esName = ".strtab"+ , esType = SHT_STRTAB+ , esFlags = 0+ , esAddr = 0+ , esAddrAlign = 1+ , esEntSize = 0+ , esN = strtabSecN+ , esLink = 0+ , esInfo = 0+ , esData = ElfSectionData stringTableData+ }+ , ElfSectionTable+ ]+```++Сгенерируем с помощью этого модуля объектный файл и попробуем его слинковать:++```+[nix-shell:examples]$ ghci +GHCi, version 8.10.4: https://www.haskell.org/ghc/ :? for help+Prelude> :l MkObj.hs HelloWorld.hs+[1 of 3] Compiling AsmAarch64 ( AsmAarch64.hs, interpreted )+[2 of 3] Compiling HelloWorld ( HelloWorld.hs, interpreted )+[3 of 3] Compiling MkObj ( MkObj.hs, interpreted )+Ok, three modules loaded.+*MkObj> import MkObj +*MkObj MkObj> import HelloWorld +*MkObj MkObj HelloWorld> elf <- mkObj helloWorld+*MkObj MkObj HelloWorld> import Data.Elf+*MkObj MkObj HelloWorld Data.Elf> bs <- serializeElf elf+*MkObj MkObj HelloWorld Data.Elf> import Data.ByteString.Lazy as BSL+*MkObj MkObj HelloWorld Data.Elf BSL> BSL.writeFile "hello.o" bs+*MkObj MkObj HelloWorld Data.Elf BSL> +Leaving GHCi.++[nix-shell:examples]$ aarch64-unknown-linux-gnu-gcc -nostdlib hello.o -o hello ++[nix-shell:examples]$ +```++Как видим, линковщик благополучно принял сгенерированный объектный файл.+Попробуем запустить результат:++```+[nix-shell:examples]$ qemu-aarch64 hello+Hello World!++[nix-shell:examples]$ +```++Работает.++## Генерация исполняемых файлов++Так как сгенерированный код для распечатки "Hello World!" является позиционно-независимым+и не ссылается на другие секции, то его можно без изменений использовать для получения+исполняемого файла+([файл `MkExe.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/MkExe.hs)):++``` Haskell+module MkExe (mkExe) where++import Control.Monad.Catch+import Control.Monad.State+import Data.Bits+import Data.Word+import Data.Singletons.Sigma++import Data.Elf+import Data.Elf.Constants+import Data.Elf.Headers++import AsmAarch64++addr :: Word64+addr = 0x400000++mkExe :: MonadCatch m => StateT CodeState m () -> m Elf+mkExe m = do+ (txt, _) <- assemble 1 m+ let+ segment = ElfSegment+ { epType = PT_LOAD+ , epFlags = PF_X .|. PF_R+ , epVirtAddr = addr+ , epPhysAddr = addr+ , epAddMemSize = 0+ , epAlign = 0x10000+ , epData =+ [ ElfHeader+ { ehData = ELFDATA2LSB+ , ehOSABI = ELFOSABI_SYSV+ , ehABIVersion = 0+ , ehType = ET_EXEC+ , ehMachine = EM_AARCH64+ , ehEntry = addr + headerSize ELFCLASS64+ , ehFlags = 0+ }+ , ElfRawData+ { edData = txt+ }+ , ElfSegmentTable+ ]+ }+ return $ SELFCLASS64 :&: ElfList [ segment ]+```++Попробуем его сгенерировать и запустить:++```+[nix-shell:examples]$ ghci +GHCi, version 8.10.4: https://www.haskell.org/ghc/ :? for help+Prelude> :l MkExe.hs HelloWorld.hs+[1 of 3] Compiling AsmAarch64 ( AsmAarch64.hs, interpreted )+[2 of 3] Compiling HelloWorld ( HelloWorld.hs, interpreted )+[3 of 3] Compiling MkExe ( MkExe.hs, interpreted )+Ok, three modules loaded.+*MkExe> import MkExe+*MkExe MkExe> import HelloWorld+*MkExe MkExe HelloWorld> elf <- mkExe helloWorld +*MkExe MkExe HelloWorld> import Data.Elf+*MkExe MkExe HelloWorld Data.Elf> bs <- serializeElf elf+*MkExe MkExe HelloWorld Data.Elf> import Data.ByteString.Lazy as BSL+*MkExe MkExe HelloWorld Data.Elf BSL> BSL.writeFile "hellox" bs+*MkExe MkExe HelloWorld Data.Elf BSL> +Leaving GHCi.++[nix-shell:examples]$ chmod +x hellox++[nix-shell:examples]$ qemu-aarch64 hellox+Hello World!++[nix-shell:examples]$ +```++Работает.
+ examples/forwardLabelExe.dump.golden view
@@ -0,0 +1,27 @@+segment {+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ VirtAddr: 0x0000000000400000+ PhysAddr: 0x0000000000400000+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000010000+ Data: + header {+ Class: ELFCLASS64+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_EXEC+ Machine: EM_AARCH64+ Entry: 0x0000000000400040+ Flags: 0x00000000+ }+ raw data {+ Data: 20 00 80 d2 61 01 00 10 62 00 80 d2 03 00 00 14 # ...a...b.......+ 01 01 00 70 82 00 80 d2 08 08 80 d2 01 00 00 d4 # ...p............+ ...+ 01 00 00 d4 00 00 00 00 6f 6b 0a 62 61 64 0a 00 # ........ok.bad..+ total: 56+ }+ segment table+}
+ examples/forwardLabelExe.layout.golden view
@@ -0,0 +1,8 @@+┌─ 0x00000000 P PT_LOAD [PF_X,PF_R]+│┎ 0x00000000 H+│┖ 0x0000003f+│╓ 0x00000040 R+│╙ 0x00000077+│┎ 0x00000078 PT (1)+│┖ 0x000000af+└─ 0x000000af
+ examples/helloWorldExe.dump.golden view
@@ -0,0 +1,25 @@+segment {+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ VirtAddr: 0x0000000000400000+ PhysAddr: 0x0000000000400000+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000010000+ Data: + header {+ Class: ELFCLASS64+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_EXEC+ Machine: EM_AARCH64+ Entry: 0x0000000000400040+ Flags: 0x00000000+ }+ raw data {+ Data: 20 00 80 d2 e1 00 00 10 a2 01 80 d2 08 08 80 d2 # ...............+ 01 00 00 d4 00 00 80 d2 a8 0b 80 d2 01 00 00 d4 # ................+ 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 0a 00 00 00 # Hello World!....+ }+ segment table+}
+ examples/helloWorldExe.layout.golden view
@@ -0,0 +1,8 @@+┌─ 0x00000000 P PT_LOAD [PF_X,PF_R]+│┎ 0x00000000 H+│┖ 0x0000003f+│╓ 0x00000040 R+│╙ 0x0000006f+│┎ 0x00000070 PT (1)+│┖ 0x000000a7+└─ 0x000000a7
+ examples/helloWorldObj.o.dump.golden view
@@ -0,0 +1,58 @@+header {+ Class: ELFCLASS64+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_REL+ Machine: EM_AARCH64+ Entry: 0x0000000000000000+ Flags: 0x00000000+}+section 1 ".text" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x0000000000000000+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 20 00 80 d2 e1 00 00 10 a2 01 80 d2 08 08 80 d2 # ...............+ 01 00 00 d4 00 00 80 d2 a8 0b 80 d2 01 00 00 d4 # ................+ 48 65 6c 6c 6f 20 57 6f 72 6c 64 21 0a # Hello World!.+}+string table section 2 ".shstrtab"+symbol table section 4 ".symtab" {+ Type: SHT_SYMTAB+ Flags: []+ Addr: 0x0000000000000000+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000018+ Info: 0x00000001+ Link: 0x00000003+ Data: + symbol "" {+ Bind: STB_Local+ Type: STT_NoType+ ShNdx: SHN_Undef+ Value: 0x0000000000000000+ Size: 0x0000000000000000+ }+ symbol "_start" {+ Bind: STB_Global+ Type: STT_NoType+ ShNdx: SHN_EXT 1+ Value: 0x0000000000000000+ Size: 0x0000000000000000+ }+}+section 3 ".strtab" {+ Type: SHT_STRTAB+ Flags: []+ Addr: 0x0000000000000000+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 5f 73 74 61 72 74 00 # ._start.+}+section table
+ examples/helloWorldObj.o.layout.golden view
@@ -0,0 +1,12 @@+┎ 0x00000000 H+┖ 0x0000003f+╓ 0x00000040 S1 ".text" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+╙ 0x0000006c+╓ 0x0000006d S2 ".shstrtab" SHT_STRTAB []+╙ 0x0000008d+╓ 0x00000090 S4 ".symtab" SHT_SYMTAB []+╙ 0x000000bf+╓ 0x000000c0 S3 ".strtab" SHT_STRTAB []+╙ 0x000000c7+┎ 0x000000c8 ST (5)+┖ 0x00000207
melf.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: melf-version: 1.0.0+version: 1.0.1 synopsis: An Elf parser description: Parser for ELF object format category: Data@@ -18,10 +18,36 @@ license-file: LICENSE build-type: Simple tested-with:- GHC == 8.10.4+ GHC == 8.10.7 extra-doc-files: ChangeLog.md README.md+ examples/README_ru.md+data-files:+ tests/testdata/orig/bloated.elf.golden+ tests/testdata/orig/bloated.elf_header.golden+ tests/testdata/orig/bloated.header.golden+ tests/testdata/orig/bloated.layout.golden+ tests/testdata/orig/bloated.strtable.golden+ tests/testdata/orig/tiny.elf.golden+ tests/testdata/orig/tiny.elf_header.golden+ tests/testdata/orig/tiny.header.golden+ tests/testdata/orig/tiny.layout.golden+ tests/testdata/orig/tiny.strtable.golden+ tests/testdata/orig/vdso.elf.golden+ tests/testdata/orig/vdso.elf_header.golden+ tests/testdata/orig/vdso.header.golden+ tests/testdata/orig/vdso.layout.golden+ tests/testdata/orig/vdso.strtable.golden+ examples/forwardLabelExe.dump.golden+ examples/forwardLabelExe.layout.golden+ examples/helloWorldExe.dump.golden+ examples/helloWorldExe.layout.golden+ examples/helloWorldObj.o.dump.golden+ examples/helloWorldObj.o.layout.golden+ testdata/orig/bloated+ testdata/orig/tiny+ testdata/orig/vdso source-repository head type: git@@ -91,11 +117,10 @@ type: exitcode-stdio-1.0 main-is: Examples.hs other-modules:- AsmAarch64+ AsmAArch64+ DummyLd ForwardLabel HelloWorld- MkExe- MkObj Paths_melf hs-source-dirs: examples
src/Data/Elf.hs view
@@ -19,9 +19,10 @@ , serializeElf -- * Misc- , getSectionData- , getString+ , getSectionData -- FIXME: Should be moved to Data.Elf.Headers (requires bumping major version)+ , getString -- FIXME: ... , elfFindSection+ , elfFindSectionByName , elfFindHeader -- * Symbol table
src/Data/Elf/PrettyPrint.hs view
@@ -99,6 +99,7 @@ printWordXX :: SingI a => WordXX a -> Doc () printWordXX = withSing printWordXXS +-- | Print ELF header. It's used in golden tests printHeader :: forall a . SingI a => HeaderXX a -> Doc () printHeader HeaderXX{..} = formatPairs@@ -149,7 +150,8 @@ , ("Align", printWordXX pAlign ) -- WordXX c ] --- | Print parsed headers. It's used in golden tests+-- | Print parsed header, section table and segment table.+-- It's used in golden tests printHeaders :: SingI a => HeaderXX a -> [SectionXX a] -> [SegmentXX a] -> Doc () printHeaders hdr ss ps = let
src/Data/Internal/Elf.hs view
@@ -370,6 +370,17 @@ f s@ElfSection{..} | esN == fromIntegral n = First $ Just s f _ = First Nothing +-- | Find section with a given name+elfFindSectionByName :: forall a m . (SingI a, MonadThrow m)+ => [ElfXX a] -- ^ Structured ELF data+ -> String -- ^ Section name+ -> m (ElfXX a) -- ^ The section in question+elfFindSectionByName elfs n = $maybeAddContext ("no section \"" ++ show n ++ "\"") maybeSection+ where+ maybeSection = getFirst $ foldMapElfList f elfs+ f s@ElfSection{..} | esName == n = First $ Just s+ f _ = First Nothing+ -- | Find ELF header elfFindHeader :: forall a m . (SingI a, MonadThrow m) => [ElfXX a] -- ^ Structured ELF data
+ testdata/orig/bloated view
binary file changed (absent → 7880 bytes)
+ testdata/orig/tiny view
binary file changed (absent → 448 bytes)
+ testdata/orig/vdso view
binary file changed (absent → 8192 bytes)
tests/Golden.hs view
@@ -241,7 +241,10 @@ ] elfsForHeader :: [String]-elfsForHeader = [ "testdata/ppc/64/du", "testdata/arm_32_lsb/arp" ]+elfsForHeader = [ "testdata/orig/bloated"+ , "testdata/orig/tiny"+ , "testdata/orig/vdso"+ ] main :: IO () main = do
+ tests/testdata/orig/bloated.elf.golden view
@@ -0,0 +1,483 @@+segment {+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ VirtAddr: 0x08048000+ PhysAddr: 0x08048000+ AddMemSize: 0x00000000+ Align: 0x00001000+ Data: + segment {+ Type: PT_EXT 1685382481+ Flags: [PF_W,PF_R]+ VirtAddr: 0x00000000+ PhysAddr: 0x00000000+ AddMemSize: 0x00000000+ Align: 0x00000010+ Data: + }+ header {+ Class: ELFCLASS32+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_EXEC+ Machine: EM_386+ Entry: 0x08048610+ Flags: 0x00000000+ }+ segment {+ Type: PT_PHDR+ Flags: [PF_X,PF_R]+ VirtAddr: 0x08048034+ PhysAddr: 0x08048034+ AddMemSize: 0x00000000+ Align: 0x00000004+ Data: + segment table+ }+ segment {+ Type: PT_INTERP+ Flags: [PF_R]+ VirtAddr: 0x08048154+ PhysAddr: 0x08048154+ AddMemSize: 0x00000000+ Align: 0x00000001+ Data: + section 1 ".interp" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC]+ Addr: 0x08048154+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 2f 6c 69 62 2f 6c 64 2d 6c 69 6e 75 78 2e 73 6f # /lib/ld-linux.so+ 2e 32 00 # .2.+ }+ }+ segment {+ Type: PT_NOTE+ Flags: [PF_R]+ VirtAddr: 0x08048168+ PhysAddr: 0x08048168+ AddMemSize: 0x00000000+ Align: 0x00000004+ Data: + section 2 ".note.ABI-tag" {+ Type: SHT_NOTE+ Flags: [SHF_ALLOC]+ Addr: 0x08048168+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 04 00 00 00 10 00 00 00 01 00 00 00 47 4e 55 00 # ............GNU.+ 00 00 00 00 02 00 00 00 06 00 00 00 20 00 00 00 # ............ ...+ }+ section 3 ".note.gnu.build-id" {+ Type: SHT_NOTE+ Flags: [SHF_ALLOC]+ Addr: 0x08048188+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 04 00 00 00 14 00 00 00 03 00 00 00 47 4e 55 00 # ............GNU.+ 58 e3 4f e8 bc 03 f9 db 4b 07 fa e5 03 1e fd d0 # X.O.....K.......+ 88 97 6f 88 # ..o.+ }+ }+ section 4 ".gnu.hash" {+ Type: SHT_EXT 1879048182+ Flags: [SHF_ALLOC]+ Addr: 0x080481ac+ AddrAlign: 0x00000004+ EntSize: 0x00000004+ Info: 0x00000000+ Link: 0x00000005+ Data: 03 00 00 00 0a 00 00 00 01 00 00 00 05 00 00 00 # ................+ 01 23 10 20 00 00 00 00 0a 00 00 00 0c 00 00 00 # .#. ............+ ac 4b e3 c0 21 fd f4 09 28 45 d5 4c 15 98 0c 43 # .K..!...(E.L...C+ }+ symbol table section 5 ".dynsym" {+ Type: SHT_DYNSYM+ Flags: [SHF_ALLOC]+ Addr: 0x080481dc+ AddrAlign: 0x00000004+ EntSize: 0x00000010+ Info: 0x00000001+ Link: 0x00000006+ Data: + symbol "" {+ Bind: STB_Local+ Type: STT_NoType+ ShNdx: SHN_Undef+ Value: 0x00000000+ Size: 0x00000000+ }+ symbol "__cxa_atexit" {+ Bind: STB_Global+ Type: STT_Func+ ShNdx: SHN_Undef+ Value: 0x00000000+ Size: 0x00000000+ }+ ...+ symbol "_ZSt4cout" {+ Bind: STB_Global+ Type: STT_Object+ ShNdx: SHN_EXT 26+ Value: 0x0804a040+ Size: 0x0000008c+ }+ total: 14+ }+ section 6 ".dynstr" {+ Type: SHT_STRTAB+ Flags: [SHF_ALLOC]+ Addr: 0x080482bc+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 6c 69 62 73 74 64 63 2b 2b 2e 73 6f 2e 36 00 # .libstdc++.so.6.+ 5f 5f 67 6d 6f 6e 5f 73 74 61 72 74 5f 5f 00 5f # __gmon_start__._+ ...+ 32 2e 30 00 47 4c 49 42 43 5f 32 2e 31 2e 33 00 # 2.0.GLIBC_2.1.3.+ total: 409+ }+ section 7 ".gnu.version" {+ Type: SHT_EXT 1879048191+ Flags: [SHF_ALLOC]+ Addr: 0x08048456+ AddrAlign: 0x00000002+ EntSize: 0x00000002+ Info: 0x00000000+ Link: 0x00000005+ Data: 00 00 02 00 00 00 00 00 03 00 04 00 00 00 03 00 # ................+ 00 00 03 00 01 00 03 00 03 00 03 00 # ............+ }+ section 8 ".gnu.version_r" {+ Type: SHT_EXT 1879048190+ Flags: [SHF_ALLOC]+ Addr: 0x08048474+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000002+ Link: 0x00000006+ Data: 01 00 01 00 01 00 00 00 10 00 00 00 20 00 00 00 # ............ ...+ 74 29 92 08 00 00 03 00 77 01 00 00 00 00 00 00 # t)......w.......+ ...+ 73 1f 69 09 00 00 02 00 8d 01 00 00 00 00 00 00 # s.i.............+ total: 80+ }+ section 9 ".rel.dyn" {+ Type: SHT_REL+ Flags: [SHF_ALLOC]+ Addr: 0x080484c4+ AddrAlign: 0x00000004+ EntSize: 0x00000008+ Info: 0x00000000+ Link: 0x00000005+ Data: fc 9f 04 08 06 02 00 00 40 a0 04 08 05 0d 00 00 # ........@.......+ }+ section 10 ".rel.plt" {+ Type: SHT_REL+ Flags: [SHF_ALLOC,SHF_EXT 64]+ Addr: 0x080484d4+ AddrAlign: 0x00000004+ EntSize: 0x00000008+ Info: 0x00000018+ Link: 0x00000005+ Data: 0c a0 04 08 07 01 00 00 10 a0 04 08 07 04 00 00 # ................+ 14 a0 04 08 07 05 00 00 18 a0 04 08 07 0c 00 00 # ................+ ...+ 20 a0 04 08 07 09 00 00 24 a0 04 08 07 0b 00 00 # .......$.......+ total: 56+ }+ section 11 ".init" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x0804850c+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 53 83 ec 08 e8 2b 01 00 00 81 c3 eb 1a 00 00 8b # S....+..........+ 83 fc ff ff ff 85 c0 74 05 e8 86 00 00 00 83 c4 # .......t........+ 08 5b c3 # .[.+ }+ section 12 ".plt" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x08048530+ AddrAlign: 0x00000010+ EntSize: 0x00000004+ Info: 0x00000000+ Link: 0x00000000+ Data: ff 35 04 a0 04 08 ff 25 08 a0 04 08 00 00 00 00 # .5.....%........+ ff 25 0c a0 04 08 68 00 00 00 00 e9 e0 ff ff ff # .%....h.........+ ...+ ff 25 24 a0 04 08 68 30 00 00 00 e9 80 ff ff ff # .%$...h0........+ total: 128+ }+ section 13 ".plt.got" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x080485b0+ AddrAlign: 0x00000008+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: ff 25 fc 9f 04 08 66 90 # .%....f.+ }+ section 14 ".text" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x080485c0+ AddrAlign: 0x00000010+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 55 89 e5 83 ec 18 8d 05 cd a0 04 08 89 04 24 e8 # U.............$.+ 7c ff ff ff 8d 05 70 85 04 08 8d 0d cd a0 04 08 # |.....p.........+ ...+ fe 75 e3 83 c4 0c 5b 5e 5f 5d c3 8d 76 00 f3 c3 # .u....[^_]..v...+ total: 530+ }+ section 15 ".fini" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x080487d4+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 53 83 ec 08 e8 63 fe ff ff 81 c3 23 18 00 00 83 # S....c.....#....+ c4 08 5b c3 # ..[.+ }+ section 16 ".rodata" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC]+ Addr: 0x080487e8+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 03 00 00 00 01 00 02 00 00 00 00 00 48 65 6c 6c # ............Hell+ 6f 20 77 6f 72 6c 64 21 00 # o world!.+ }+ segment {+ Type: PT_EXT 1685382480+ Flags: [PF_R]+ VirtAddr: 0x08048804+ PhysAddr: 0x08048804+ AddMemSize: 0x00000000+ Align: 0x00000004+ Data: + section 17 ".eh_frame_hdr" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC]+ Addr: 0x08048804+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 01 1b 03 3b 38 00 00 00 06 00 00 00 2c fd ff ff # ...;8.......,...+ 54 00 00 00 bc fd ff ff 78 00 00 00 fc fd ff ff # T.......x.......+ ...+ 6c ff ff ff cc 00 00 00 cc ff ff ff 18 01 00 00 # l...............+ total: 60+ }+ }+ section 18 ".eh_frame" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC]+ Addr: 0x08048840+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 14 00 00 00 00 00 00 00 01 7a 52 00 01 7c 08 01 # .........zR..|..+ 1b 0c 04 04 88 01 00 00 20 00 00 00 1c 00 00 00 # ........ .......+ ...+ ac fe ff ff 02 00 00 00 00 00 00 00 00 00 00 00 # ................+ total: 244+ }+}+segment {+ Type: PT_LOAD+ Flags: [PF_W,PF_R]+ VirtAddr: 0x08049eec+ PhysAddr: 0x08049eec+ AddMemSize: 0x000000a4+ Align: 0x00001000+ Data: + segment {+ Type: PT_EXT 1685382482+ Flags: [PF_R]+ VirtAddr: 0x08049eec+ PhysAddr: 0x08049eec+ AddMemSize: 0x00000000+ Align: 0x00000001+ Data: + section 19 ".init_array" {+ Type: SHT_EXT 14+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x08049eec+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: e0 86 04 08 00 86 04 08 # ........+ }+ section 20 ".fini_array" {+ Type: SHT_EXT 15+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x08049ef4+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: c0 86 04 08 # ....+ }+ section 21 ".jcr" {+ Type: SHT_PROGBITS+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x08049ef8+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 00 00 00 # ....+ }+ segment {+ Type: PT_DYNAMIC+ Flags: [PF_W,PF_R]+ VirtAddr: 0x08049efc+ PhysAddr: 0x08049efc+ AddMemSize: 0x00000000+ Align: 0x00000004+ Data: + section 22 ".dynamic" {+ Type: SHT_DYNAMIC+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x08049efc+ AddrAlign: 0x00000004+ EntSize: 0x00000008+ Info: 0x00000000+ Link: 0x00000006+ Data: 01 00 00 00 01 00 00 00 01 00 00 00 27 01 00 00 # ............'...+ 01 00 00 00 31 01 00 00 01 00 00 00 3f 01 00 00 # ....1.......?...+ ...+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # ................+ total: 256+ }+ }+ section 23 ".got" {+ Type: SHT_PROGBITS+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x08049ffc+ AddrAlign: 0x00000004+ EntSize: 0x00000004+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 00 00 00 # ....+ }+ }+ section 24 ".got.plt" {+ Type: SHT_PROGBITS+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x0804a000+ AddrAlign: 0x00000004+ EntSize: 0x00000004+ Info: 0x00000000+ Link: 0x00000000+ Data: fc 9e 04 08 00 00 00 00 00 00 00 00 46 85 04 08 # ............F...+ 56 85 04 08 66 85 04 08 76 85 04 08 86 85 04 08 # V...f...v.......+ 96 85 04 08 a6 85 04 08 # ........+ }+ section 25 ".data" {+ Type: SHT_PROGBITS+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x0804a028+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 00 00 00 # ....+ }+}+section 26 ".bss" {+ Type: SHT_NOBITS+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x0804a040+ AddrAlign: 0x00000020+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: +}+section 27 ".comment" {+ Type: SHT_PROGBITS+ Flags: [SHF_EXT 16,SHF_EXT 32]+ Addr: 0x00000000+ AddrAlign: 0x00000001+ EntSize: 0x00000001+ Info: 0x00000000+ Link: 0x00000000+ Data: 47 43 43 3a 20 28 47 4e 55 29 20 36 2e 33 2e 31 # GCC: (GNU) 6.3.1+ 20 32 30 31 36 31 32 32 31 20 28 52 65 64 20 48 # 20161221 (Red H+ ...+ 45 41 53 45 5f 33 38 31 2f 66 69 6e 61 6c 29 00 # EASE_381/final).+ total: 89+}+symbol table section 29 ".symtab" {+ Type: SHT_SYMTAB+ Flags: []+ Addr: 0x00000000+ AddrAlign: 0x00000004+ EntSize: 0x00000010+ Info: 0x00000032+ Link: 0x0000001e+ Data: + symbol "" {+ Bind: STB_Local+ Type: STT_NoType+ ShNdx: SHN_Undef+ Value: 0x00000000+ Size: 0x00000000+ }+ symbol "" {+ Bind: STB_Local+ Type: STT_Section+ ShNdx: SHN_EXT 1+ Value: 0x08048154+ Size: 0x00000000+ }+ ...+ symbol "_init" {+ Bind: STB_Global+ Type: STT_Func+ ShNdx: SHN_EXT 11+ Value: 0x0804850c+ Size: 0x00000000+ }+ total: 78+}+section 30 ".strtab" {+ Type: SHT_STRTAB+ Flags: []+ Addr: 0x00000000+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 5f 47 4c 4f 42 41 4c 5f 5f 73 75 62 5f 49 5f # ._GLOBAL__sub_I_+ 62 6c 6f 61 74 65 64 2e 63 70 70 00 5f 5a 53 74 # bloated.cpp._ZSt+ ...+ 33 2e 34 00 5f 65 64 61 74 61 00 6d 61 69 6e 00 # 3.4._edata.main.+ total: 891+}+string table section 28 ".shstrtab"+section table
+ tests/testdata/orig/bloated.elf_header.golden view
@@ -0,0 +1,15 @@+Class: ELFCLASS32+Data: ELFDATA2LSB+OSABI: ELFOSABI_SYSV+ABIVersion: 0+Type: ET_EXEC+Machine: EM_386+Entry: 0x08048610+PhOff: 0x00000034+ShOff: 0x000019f0+Flags: 0x00000000+PhEntSize: 0x0020+PhNum: 9+ShEntSize: 0x0028+ShNum: 31+ShStrNdx: SHN_EXT 28
+ tests/testdata/orig/bloated.header.golden view
@@ -0,0 +1,437 @@+Header: Class: ELFCLASS32+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_EXEC+ Machine: EM_386+ Entry: 0x08048610+ PhOff: 0x00000034+ ShOff: 0x000019f0+ Flags: 0x00000000+ PhEntSize: 0x0020+ PhNum: 9+ ShEntSize: 0x0028+ ShNum: 31+ ShStrNdx: SHN_EXT 28+Sections: - N: 0+ Name: 0+ Type: SHT_NULL+ Flags: 0x00000000+ Addr: 0x00000000+ Offset: 0x00000000+ Size: 0x00000000+ Link: 0+ Info: 0+ AddrAlign: 0x00000000+ EntSize: 0x00000000+ - N: 1+ Name: 27+ Type: SHT_PROGBITS+ Flags: 0x00000002+ Addr: 0x08048154+ Offset: 0x00000154+ Size: 0x00000013+ Link: 0+ Info: 0+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ - N: 2+ Name: 35+ Type: SHT_NOTE+ Flags: 0x00000002+ Addr: 0x08048168+ Offset: 0x00000168+ Size: 0x00000020+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 3+ Name: 49+ Type: SHT_NOTE+ Flags: 0x00000002+ Addr: 0x08048188+ Offset: 0x00000188+ Size: 0x00000024+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 4+ Name: 68+ Type: SHT_EXT 1879048182+ Flags: 0x00000002+ Addr: 0x080481ac+ Offset: 0x000001ac+ Size: 0x00000030+ Link: 5+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000004+ - N: 5+ Name: 78+ Type: SHT_DYNSYM+ Flags: 0x00000002+ Addr: 0x080481dc+ Offset: 0x000001dc+ Size: 0x000000e0+ Link: 6+ Info: 1+ AddrAlign: 0x00000004+ EntSize: 0x00000010+ - N: 6+ Name: 86+ Type: SHT_STRTAB+ Flags: 0x00000002+ Addr: 0x080482bc+ Offset: 0x000002bc+ Size: 0x00000199+ Link: 0+ Info: 0+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ - N: 7+ Name: 94+ Type: SHT_EXT 1879048191+ Flags: 0x00000002+ Addr: 0x08048456+ Offset: 0x00000456+ Size: 0x0000001c+ Link: 5+ Info: 0+ AddrAlign: 0x00000002+ EntSize: 0x00000002+ - N: 8+ Name: 107+ Type: SHT_EXT 1879048190+ Flags: 0x00000002+ Addr: 0x08048474+ Offset: 0x00000474+ Size: 0x00000050+ Link: 6+ Info: 2+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 9+ Name: 122+ Type: SHT_REL+ Flags: 0x00000002+ Addr: 0x080484c4+ Offset: 0x000004c4+ Size: 0x00000010+ Link: 5+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000008+ - N: 10+ Name: 131+ Type: SHT_REL+ Flags: 0x00000042+ Addr: 0x080484d4+ Offset: 0x000004d4+ Size: 0x00000038+ Link: 5+ Info: 24+ AddrAlign: 0x00000004+ EntSize: 0x00000008+ - N: 11+ Name: 140+ Type: SHT_PROGBITS+ Flags: 0x00000006+ Addr: 0x0804850c+ Offset: 0x0000050c+ Size: 0x00000023+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 12+ Name: 135+ Type: SHT_PROGBITS+ Flags: 0x00000006+ Addr: 0x08048530+ Offset: 0x00000530+ Size: 0x00000080+ Link: 0+ Info: 0+ AddrAlign: 0x00000010+ EntSize: 0x00000004+ - N: 13+ Name: 146+ Type: SHT_PROGBITS+ Flags: 0x00000006+ Addr: 0x080485b0+ Offset: 0x000005b0+ Size: 0x00000008+ Link: 0+ Info: 0+ AddrAlign: 0x00000008+ EntSize: 0x00000000+ - N: 14+ Name: 155+ Type: SHT_PROGBITS+ Flags: 0x00000006+ Addr: 0x080485c0+ Offset: 0x000005c0+ Size: 0x00000212+ Link: 0+ Info: 0+ AddrAlign: 0x00000010+ EntSize: 0x00000000+ - N: 15+ Name: 161+ Type: SHT_PROGBITS+ Flags: 0x00000006+ Addr: 0x080487d4+ Offset: 0x000007d4+ Size: 0x00000014+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 16+ Name: 167+ Type: SHT_PROGBITS+ Flags: 0x00000002+ Addr: 0x080487e8+ Offset: 0x000007e8+ Size: 0x00000019+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 17+ Name: 175+ Type: SHT_PROGBITS+ Flags: 0x00000002+ Addr: 0x08048804+ Offset: 0x00000804+ Size: 0x0000003c+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 18+ Name: 189+ Type: SHT_PROGBITS+ Flags: 0x00000002+ Addr: 0x08048840+ Offset: 0x00000840+ Size: 0x000000f4+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 19+ Name: 199+ Type: SHT_EXT 14+ Flags: 0x00000003+ Addr: 0x08049eec+ Offset: 0x00000eec+ Size: 0x00000008+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 20+ Name: 211+ Type: SHT_EXT 15+ Flags: 0x00000003+ Addr: 0x08049ef4+ Offset: 0x00000ef4+ Size: 0x00000004+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 21+ Name: 223+ Type: SHT_PROGBITS+ Flags: 0x00000003+ Addr: 0x08049ef8+ Offset: 0x00000ef8+ Size: 0x00000004+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000000+ - N: 22+ Name: 228+ Type: SHT_DYNAMIC+ Flags: 0x00000003+ Addr: 0x08049efc+ Offset: 0x00000efc+ Size: 0x00000100+ Link: 6+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000008+ - N: 23+ Name: 150+ Type: SHT_PROGBITS+ Flags: 0x00000003+ Addr: 0x08049ffc+ Offset: 0x00000ffc+ Size: 0x00000004+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000004+ - N: 24+ Name: 237+ Type: SHT_PROGBITS+ Flags: 0x00000003+ Addr: 0x0804a000+ Offset: 0x00001000+ Size: 0x00000028+ Link: 0+ Info: 0+ AddrAlign: 0x00000004+ EntSize: 0x00000004+ - N: 25+ Name: 246+ Type: SHT_PROGBITS+ Flags: 0x00000003+ Addr: 0x0804a028+ Offset: 0x00001028+ Size: 0x00000004+ Link: 0+ Info: 0+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ - N: 26+ Name: 252+ Type: SHT_NOBITS+ Flags: 0x00000003+ Addr: 0x0804a040+ Offset: 0x0000102c+ Size: 0x00000090+ Link: 0+ Info: 0+ AddrAlign: 0x00000020+ EntSize: 0x00000000+ - N: 27+ Name: 257+ Type: SHT_PROGBITS+ Flags: 0x00000030+ Addr: 0x00000000+ Offset: 0x0000102c+ Size: 0x00000059+ Link: 0+ Info: 0+ AddrAlign: 0x00000001+ EntSize: 0x00000001+ - N: 28+ Name: 17+ Type: SHT_STRTAB+ Flags: 0x00000000+ Addr: 0x00000000+ Offset: 0x000018e3+ Size: 0x0000010a+ Link: 0+ Info: 0+ AddrAlign: 0x00000001+ EntSize: 0x00000000+ - N: 29+ Name: 1+ Type: SHT_SYMTAB+ Flags: 0x00000000+ Addr: 0x00000000+ Offset: 0x00001088+ Size: 0x000004e0+ Link: 30+ Info: 50+ AddrAlign: 0x00000004+ EntSize: 0x00000010+ - N: 30+ Name: 9+ Type: SHT_STRTAB+ Flags: 0x00000000+ Addr: 0x00000000+ Offset: 0x00001568+ Size: 0x0000037b+ Link: 0+ Info: 0+ AddrAlign: 0x00000001+ EntSize: 0x00000000+Segments: - N: 0+ Type: PT_PHDR+ Flags: [PF_X,PF_R]+ Offset: 0x00000034+ VirtAddr: 0x08048034+ PhysAddr: 0x08048034+ FileSize: 0x00000120+ MemSize: 0x00000120+ Align: 0x00000004+ - N: 1+ Type: PT_INTERP+ Flags: [PF_R]+ Offset: 0x00000154+ VirtAddr: 0x08048154+ PhysAddr: 0x08048154+ FileSize: 0x00000013+ MemSize: 0x00000013+ Align: 0x00000001+ - N: 2+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ Offset: 0x00000000+ VirtAddr: 0x08048000+ PhysAddr: 0x08048000+ FileSize: 0x00000934+ MemSize: 0x00000934+ Align: 0x00001000+ - N: 3+ Type: PT_LOAD+ Flags: [PF_W,PF_R]+ Offset: 0x00000eec+ VirtAddr: 0x08049eec+ PhysAddr: 0x08049eec+ FileSize: 0x00000140+ MemSize: 0x000001e4+ Align: 0x00001000+ - N: 4+ Type: PT_DYNAMIC+ Flags: [PF_W,PF_R]+ Offset: 0x00000efc+ VirtAddr: 0x08049efc+ PhysAddr: 0x08049efc+ FileSize: 0x00000100+ MemSize: 0x00000100+ Align: 0x00000004+ - N: 5+ Type: PT_NOTE+ Flags: [PF_R]+ Offset: 0x00000168+ VirtAddr: 0x08048168+ PhysAddr: 0x08048168+ FileSize: 0x00000044+ MemSize: 0x00000044+ Align: 0x00000004+ - N: 6+ Type: PT_EXT 1685382480+ Flags: [PF_R]+ Offset: 0x00000804+ VirtAddr: 0x08048804+ PhysAddr: 0x08048804+ FileSize: 0x0000003c+ MemSize: 0x0000003c+ Align: 0x00000004+ - N: 7+ Type: PT_EXT 1685382481+ Flags: [PF_W,PF_R]+ Offset: 0x00000000+ VirtAddr: 0x00000000+ PhysAddr: 0x00000000+ FileSize: 0x00000000+ MemSize: 0x00000000+ Align: 0x00000010+ - N: 8+ Type: PT_EXT 1685382482+ Flags: [PF_R]+ Offset: 0x00000eec+ VirtAddr: 0x08049eec+ PhysAddr: 0x08049eec+ FileSize: 0x00000114+ MemSize: 0x00000114+ Align: 0x00000001
+ tests/testdata/orig/bloated.layout.golden view
@@ -0,0 +1,82 @@+ ┌── 0x00000000 P PT_LOAD [PF_X,PF_R]+ │ - 0x00000000 P PT_EXT 1685382481 [PF_W,PF_R]+ │ ┎ 0x00000000 H+ │ ┖ 0x00000033+ │┌─ 0x00000034 P PT_PHDR [PF_X,PF_R]+ ││┎ 0x00000034 PT (9)+ ││┖ 0x00000153+ │└─ 0x00000153+ │┌─ 0x00000154 P PT_INTERP [PF_R]+ ││╓ 0x00000154 S1 ".interp" SHT_PROGBITS [SHF_ALLOC]+ ││╙ 0x00000166+ │└─ 0x00000166+ │┌─ 0x00000168 P PT_NOTE [PF_R]+ ││╓ 0x00000168 S2 ".note.ABI-tag" SHT_NOTE [SHF_ALLOC]+ ││╙ 0x00000187+ ││╓ 0x00000188 S3 ".note.gnu.build-id" SHT_NOTE [SHF_ALLOC]+ ││╙ 0x000001ab+ │└─ 0x000001ab+ │ ╓ 0x000001ac S4 ".gnu.hash" SHT_EXT 1879048182 [SHF_ALLOC]+ │ ╙ 0x000001db+ │ ╓ 0x000001dc S5 ".dynsym" SHT_DYNSYM [SHF_ALLOC]+ │ ╙ 0x000002bb+ │ ╓ 0x000002bc S6 ".dynstr" SHT_STRTAB [SHF_ALLOC]+ │ ╙ 0x00000454+ │ ╓ 0x00000456 S7 ".gnu.version" SHT_EXT 1879048191 [SHF_ALLOC]+ │ ╙ 0x00000471+ │ ╓ 0x00000474 S8 ".gnu.version_r" SHT_EXT 1879048190 [SHF_ALLOC]+ │ ╙ 0x000004c3+ │ ╓ 0x000004c4 S9 ".rel.dyn" SHT_REL [SHF_ALLOC]+ │ ╙ 0x000004d3+ │ ╓ 0x000004d4 S10 ".rel.plt" SHT_REL [SHF_ALLOC,SHF_EXT 64]+ │ ╙ 0x0000050b+ │ ╓ 0x0000050c S11 ".init" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+ │ ╙ 0x0000052e+ │ ╓ 0x00000530 S12 ".plt" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+ │ ╙ 0x000005af+ │ ╓ 0x000005b0 S13 ".plt.got" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+ │ ╙ 0x000005b7+ │ ╓ 0x000005c0 S14 ".text" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+ │ ╙ 0x000007d1+ │ ╓ 0x000007d4 S15 ".fini" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+ │ ╙ 0x000007e7+ │ ╓ 0x000007e8 S16 ".rodata" SHT_PROGBITS [SHF_ALLOC]+ │ ╙ 0x00000800+ │┌─ 0x00000804 P PT_EXT 1685382480 [PF_R]+ ││╓ 0x00000804 S17 ".eh_frame_hdr" SHT_PROGBITS [SHF_ALLOC]+ ││╙ 0x0000083f+ │└─ 0x0000083f+ │ ╓ 0x00000840 S18 ".eh_frame" SHT_PROGBITS [SHF_ALLOC]+ │ ╙ 0x00000933+ └── 0x00000933+┌─── 0x00000eec P PT_LOAD [PF_W,PF_R]+│┌── 0x00000eec P PT_EXT 1685382482 [PF_R]+││ ╓ 0x00000eec S19 ".init_array" SHT_EXT 14 [SHF_WRITE,SHF_ALLOC]+││ ╙ 0x00000ef3+││ ╓ 0x00000ef4 S20 ".fini_array" SHT_EXT 15 [SHF_WRITE,SHF_ALLOC]+││ ╙ 0x00000ef7+││ ╓ 0x00000ef8 S21 ".jcr" SHT_PROGBITS [SHF_WRITE,SHF_ALLOC]+││ ╙ 0x00000efb+││┌─ 0x00000efc P PT_DYNAMIC [PF_W,PF_R]+│││╓ 0x00000efc S22 ".dynamic" SHT_DYNAMIC [SHF_WRITE,SHF_ALLOC]+│││╙ 0x00000ffb+││└─ 0x00000ffb+││ ╓ 0x00000ffc S23 ".got" SHT_PROGBITS [SHF_WRITE,SHF_ALLOC]+││ ╙ 0x00000fff+│└── 0x00000fff+│ ╓ 0x00001000 S24 ".got.plt" SHT_PROGBITS [SHF_WRITE,SHF_ALLOC]+│ ╙ 0x00001027+│ ╓ 0x00001028 S25 ".data" SHT_PROGBITS [SHF_WRITE,SHF_ALLOC]+│ ╙ 0x0000102b+└─── 0x0000102b+ - 0x0000102c S26 ".bss" SHT_NOBITS [SHF_WRITE,SHF_ALLOC]+ ╓ 0x0000102c S27 ".comment" SHT_PROGBITS [SHF_EXT 16,SHF_EXT 32]+ ╙ 0x00001084+ ╓ 0x00001088 S29 ".symtab" SHT_SYMTAB []+ ╙ 0x00001567+ ╓ 0x00001568 S30 ".strtab" SHT_STRTAB []+ ╙ 0x000018e2+ ╓ 0x000018e3 S28 ".shstrtab" SHT_STRTAB []+ ╙ 0x000019ec+ ┎ 0x000019f0 ST (31)+ ┖ 0x00001ec7
+ tests/testdata/orig/bloated.strtable.golden view
@@ -0,0 +1,29 @@+<>+<.bss>+<.comment>+<.data>+<.dynamic>+<.dynstr>+<.dynsym>+<.eh_frame>+<.eh_frame_hdr>+<.fini>+<.fini_array>+<.gnu.hash>+<.gnu.version>+<.gnu.version_r>+<.got.plt>+<.init>+<.init_array>+<.interp>+<.jcr>+<.note.ABI-tag>+<.note.gnu.build-id>+<.plt.got>+<.rel.dyn>+<.rel.plt>+<.rodata>+<.shstrtab>+<.strtab>+<.symtab>+<.text>
+ tests/testdata/orig/tiny.elf.golden view
@@ -0,0 +1,45 @@+segment {+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ VirtAddr: 0x0000000000400000+ PhysAddr: 0x0000000000400000+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000200000+ Data: + segment {+ Type: PT_NOTE+ Flags: [PF_R]+ VirtAddr: 0x0000000000000000+ PhysAddr: 0x0000000000000000+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000000008+ Data: + }+ header {+ Class: ELFCLASS64+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_EXEC+ Machine: EM_X86_64+ Entry: 0x00000000004000e0+ Flags: 0x00000000+ }+ segment table+ raw align {+ Offset: 0x00000000000000e0+ Align: 0x0000000000200000+ }+ section 1 ".text" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x00000000004000e0+ AddrAlign: 0x0000000000000010+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: bb 00 00 00 00 b8 01 00 00 00 cd 80 # ............+ }+}+string table section 2 ".shstrtab"+section table
+ tests/testdata/orig/tiny.elf_header.golden view
@@ -0,0 +1,15 @@+Class: ELFCLASS64+Data: ELFDATA2LSB+OSABI: ELFOSABI_SYSV+ABIVersion: 0+Type: ET_EXEC+Machine: EM_X86_64+Entry: 0x00000000004000e0+PhOff: 0x0000000000000040+ShOff: 0x0000000000000100+Flags: 0x00000000+PhEntSize: 0x0038+PhNum: 2+ShEntSize: 0x0040+ShNum: 3+ShStrNdx: SHN_EXT 2
+ tests/testdata/orig/tiny.header.golden view
@@ -0,0 +1,66 @@+Header: Class: ELFCLASS64+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_EXEC+ Machine: EM_X86_64+ Entry: 0x00000000004000e0+ PhOff: 0x0000000000000040+ ShOff: 0x0000000000000100+ Flags: 0x00000000+ PhEntSize: 0x0038+ PhNum: 2+ ShEntSize: 0x0040+ ShNum: 3+ ShStrNdx: SHN_EXT 2+Sections: - N: 0+ Name: 0+ Type: SHT_NULL+ Flags: 0x0000000000000000+ Addr: 0x0000000000000000+ Offset: 0x0000000000000000+ Size: 0x0000000000000000+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000000+ EntSize: 0x0000000000000000+ - N: 1+ Name: 11+ Type: SHT_PROGBITS+ Flags: 0x0000000000000006+ Addr: 0x00000000004000e0+ Offset: 0x00000000000000e0+ Size: 0x000000000000000c+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000010+ EntSize: 0x0000000000000000+ - N: 2+ Name: 1+ Type: SHT_STRTAB+ Flags: 0x0000000000000000+ Addr: 0x0000000000000000+ Offset: 0x00000000000000ec+ Size: 0x0000000000000011+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+Segments: - N: 0+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ Offset: 0x0000000000000000+ VirtAddr: 0x0000000000400000+ PhysAddr: 0x0000000000400000+ FileSize: 0x00000000000000ec+ MemSize: 0x00000000000000ec+ Align: 0x0000000000200000+ - N: 1+ Type: PT_NOTE+ Flags: [PF_R]+ Offset: 0x0000000000000000+ VirtAddr: 0x0000000000000000+ PhysAddr: 0x0000000000000000+ FileSize: 0x0000000000000000+ MemSize: 0x0000000000000000+ Align: 0x0000000000000008
+ tests/testdata/orig/tiny.layout.golden view
@@ -0,0 +1,13 @@+┌─ 0x00000000 P PT_LOAD [PF_X,PF_R]+│- 0x00000000 P PT_NOTE [PF_R]+│┎ 0x00000000 H+│┖ 0x0000003f+│┎ 0x00000040 PT (2)+│┖ 0x000000af+│╓ 0x000000e0 S1 ".text" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+│╙ 0x000000eb+└─ 0x000000eb+ ╓ 0x000000ec S2 ".shstrtab" SHT_STRTAB []+ ╙ 0x000000fc+ ┎ 0x00000100 ST (3)+ ┖ 0x000001bf
+ tests/testdata/orig/tiny.strtable.golden view
@@ -0,0 +1,3 @@+<>+<.shstrtab>+<.text>
+ tests/testdata/orig/vdso.elf.golden view
@@ -0,0 +1,271 @@+segment {+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ VirtAddr: 0x0000000000000000+ PhysAddr: 0x0000000000000000+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000001000+ Data: + header {+ Class: ELFCLASS64+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_DYN+ Machine: EM_X86_64+ Entry: 0x0000000000000970+ Flags: 0x00000000+ }+ segment table+ section 1 ".hash" {+ Type: SHT_HASH+ Flags: [SHF_ALLOC]+ Addr: 0x0000000000000120+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000004+ Info: 0x00000000+ Link: 0x00000003+ Data: 03 00 00 00 0a 00 00 00 04 00 00 00 03 00 00 00 # ................+ 06 00 00 00 00 00 00 00 00 00 00 00 07 00 00 00 # ................+ ...+ 05 00 00 00 00 00 00 00 02 00 00 00 08 00 00 00 # ................+ total: 60+ }+ section 2 ".gnu.hash" {+ Type: SHT_EXT 1879048182+ Flags: [SHF_ALLOC]+ Addr: 0x0000000000000160+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000003+ Data: 03 00 00 00 01 00 00 00 01 00 00 00 06 00 00 00 # ................+ 81 34 30 01 46 65 00 81 01 00 00 00 05 00 00 00 # .40.Fe..........+ ...+ 19 a3 43 6e 8a 2a c6 26 26 b0 62 65 6d 58 87 ff # ..Cn.*.&&.bemX..+ total: 72+ }+ symbol table section 3 ".dynsym" {+ Type: SHT_DYNSYM+ Flags: [SHF_ALLOC]+ Addr: 0x00000000000001a8+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000018+ Info: 0x00000001+ Link: 0x00000004+ Data: + symbol "" {+ Bind: STB_Local+ Type: STT_NoType+ ShNdx: SHN_Undef+ Value: 0x0000000000000000+ Size: 0x0000000000000000+ }+ symbol "clock_gettime" {+ Bind: STB_Weak+ Type: STT_Func+ ShNdx: SHN_EXT 12+ Value: 0x0000000000000a30+ Size: 0x0000000000000305+ }+ ...+ symbol "getcpu" {+ Bind: STB_Weak+ Type: STT_Func+ ShNdx: SHN_EXT 12+ Value: 0x0000000000000f30+ Size: 0x000000000000002a+ }+ total: 10+ }+ section 4 ".dynstr" {+ Type: SHT_STRTAB+ Flags: [SHF_ALLOC]+ Addr: 0x0000000000000298+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 5f 5f 76 64 73 6f 5f 63 6c 6f 63 6b 5f 67 65 # .__vdso_clock_ge+ 74 74 69 6d 65 00 5f 5f 76 64 73 6f 5f 67 65 74 # ttime.__vdso_get+ ...+ 2e 73 6f 2e 31 00 4c 49 4e 55 58 5f 32 2e 36 00 # .so.1.LINUX_2.6.+ total: 94+ }+ section 5 ".gnu.version" {+ Type: SHT_EXT 1879048191+ Flags: [SHF_ALLOC]+ Addr: 0x00000000000002f6+ AddrAlign: 0x0000000000000002+ EntSize: 0x0000000000000002+ Info: 0x00000000+ Link: 0x00000003+ Data: 00 00 02 00 02 00 02 00 02 00 02 00 02 00 02 00 # ................+ 02 00 02 00 # ....+ }+ section 6 ".gnu.version_d" {+ Type: SHT_EXT 1879048189+ Flags: [SHF_ALLOC]+ Addr: 0x0000000000000310+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ Info: 0x00000002+ Link: 0x00000004+ Data: 01 00 01 00 01 00 01 00 a1 bf ee 0d 14 00 00 00 # ................+ 1c 00 00 00 44 00 00 00 00 00 00 00 01 00 00 00 # ....D...........+ ...+ 14 00 00 00 00 00 00 00 54 00 00 00 00 00 00 00 # ........T.......+ total: 56+ }+ segment {+ Type: PT_DYNAMIC+ Flags: [PF_R]+ VirtAddr: 0x0000000000000348+ PhysAddr: 0x0000000000000348+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000000008+ Data: + section 7 ".dynamic" {+ Type: SHT_DYNAMIC+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x0000000000000348+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000010+ Info: 0x00000000+ Link: 0x00000004+ Data: 0e 00 00 00 00 00 00 00 44 00 00 00 00 00 00 00 # ........D.......+ 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # ................+ ...+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # ................+ total: 288+ }+ }+ section 8 ".rodata" {+ Type: SHT_PROGBITS+ Flags: [SHF_WRITE,SHF_ALLOC]+ Addr: 0x0000000000000468+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # ................+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # ................+ ...+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 # ................+ total: 832+ }+ segment {+ Type: PT_NOTE+ Flags: [PF_R]+ VirtAddr: 0x00000000000007a8+ PhysAddr: 0x00000000000007a8+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000000004+ Data: + section 9 ".note" {+ Type: SHT_NOTE+ Flags: [SHF_ALLOC]+ Addr: 0x00000000000007a8+ AddrAlign: 0x0000000000000004+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 06 00 00 00 04 00 00 00 00 00 00 00 4c 69 6e 75 # ............Linu+ 78 00 00 00 12 0f 04 00 04 00 00 00 14 00 00 00 # x...............+ ...+ 22 98 2b 1f 74 78 1a 66 3b 95 c6 9b e4 82 95 89 # ".+.tx.f;.......+ total: 60+ }+ }+ segment {+ Type: PT_EXT 1685382480+ Flags: [PF_R]+ VirtAddr: 0x00000000000007e4+ PhysAddr: 0x00000000000007e4+ AddMemSize: 0x0000000000000000+ Align: 0x0000000000000004+ Data: + section 10 ".eh_frame_hdr" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC]+ Addr: 0x00000000000007e4+ AddrAlign: 0x0000000000000004+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 01 1b 03 3b 38 00 00 00 06 00 00 00 8c 01 00 00 # ...;8...........+ 54 00 00 00 bc 01 00 00 7c 00 00 00 4c 02 00 00 # T.......|...L...+ ...+ 2c 07 00 00 44 01 00 00 4c 07 00 00 64 01 00 00 # ,...D...L...d...+ total: 60+ }+ }+ section 11 ".eh_frame" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC]+ Addr: 0x0000000000000820+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 14 00 00 00 00 00 00 00 01 7a 52 00 01 78 10 01 # .........zR..x..+ 1b 0c 07 08 90 01 00 00 24 00 00 00 1c 00 00 00 # ........$.......+ ...+ 00 41 0e 10 86 02 48 0d 06 60 c6 0c 07 08 00 00 # .A....H..`......+ total: 328+ }+ section 12 ".text" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x0000000000000970+ AddrAlign: 0x0000000000000010+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 55 48 89 e5 0f ae e8 0f 31 48 c1 e2 20 48 09 d0 # UH......1H.. H..+ 48 8b 15 01 c7 ff ff 48 39 c2 77 02 5d c3 48 89 # H......H9.w.].H.+ ...+ 89 17 48 85 f6 74 05 c1 e8 0c 89 06 31 c0 5d c3 # ..H..t......1.].+ total: 1514+ }+ section 13 ".altinstructions" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC]+ Addr: 0x0000000000000f5a+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 1a fa ff ff 8b 00 00 00 71 00 03 03 03 0d fa ff # ........q.......+ ff 81 00 00 00 72 00 03 03 03 48 fa ff ff 77 00 # .....r....H...w.+ ...+ 03 03 03 5d ff ff ff 27 00 00 00 16 02 04 04 01 # ...]...'........+ total: 143+ }+ section 14 ".altinstr_replacement" {+ Type: SHT_PROGBITS+ Flags: [SHF_ALLOC,SHF_EXECINSTR]+ Addr: 0x0000000000000fe9+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+ Info: 0x00000000+ Link: 0x00000000+ Data: 0f ae f0 0f ae e8 0f ae f0 0f ae e8 0f ae f0 0f # ................+ ae e8 0f ae f0 0f ae e8 0f ae f0 0f ae e8 f3 0f # ................+ c7 f8 # ..+ }+}+section 15 ".comment" {+ Type: SHT_PROGBITS+ Flags: [SHF_EXT 16,SHF_EXT 32]+ Addr: 0x0000000000000000+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000001+ Info: 0x00000000+ Link: 0x00000000+ Data: 47 43 43 3a 20 28 55 62 75 6e 74 75 20 37 2e 33 # GCC: (Ubuntu 7.3+ 2e 30 2d 31 36 75 62 75 6e 74 75 33 29 20 37 2e # .0-16ubuntu3) 7.+ 33 2e 30 00 # 3.0.+}+string table section 16 ".shstrtab"+section table
+ tests/testdata/orig/vdso.elf_header.golden view
@@ -0,0 +1,15 @@+Class: ELFCLASS64+Data: ELFDATA2LSB+OSABI: ELFOSABI_SYSV+ABIVersion: 0+Type: ET_DYN+Machine: EM_X86_64+Entry: 0x0000000000000970+PhOff: 0x0000000000000040+ShOff: 0x00000000000010d8+Flags: 0x00000000+PhEntSize: 0x0038+PhNum: 4+ShEntSize: 0x0040+ShNum: 17+ShStrNdx: SHN_EXT 16
+ tests/testdata/orig/vdso.header.golden view
@@ -0,0 +1,238 @@+Header: Class: ELFCLASS64+ Data: ELFDATA2LSB+ OSABI: ELFOSABI_SYSV+ ABIVersion: 0+ Type: ET_DYN+ Machine: EM_X86_64+ Entry: 0x0000000000000970+ PhOff: 0x0000000000000040+ ShOff: 0x00000000000010d8+ Flags: 0x00000000+ PhEntSize: 0x0038+ PhNum: 4+ ShEntSize: 0x0040+ ShNum: 17+ ShStrNdx: SHN_EXT 16+Sections: - N: 0+ Name: 0+ Type: SHT_NULL+ Flags: 0x0000000000000000+ Addr: 0x0000000000000000+ Offset: 0x0000000000000000+ Size: 0x0000000000000000+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000000+ EntSize: 0x0000000000000000+ - N: 1+ Name: 15+ Type: SHT_HASH+ Flags: 0x0000000000000002+ Addr: 0x0000000000000120+ Offset: 0x0000000000000120+ Size: 0x000000000000003c+ Link: 3+ Info: 0+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000004+ - N: 2+ Name: 11+ Type: SHT_EXT 1879048182+ Flags: 0x0000000000000002+ Addr: 0x0000000000000160+ Offset: 0x0000000000000160+ Size: 0x0000000000000048+ Link: 3+ Info: 0+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ - N: 3+ Name: 21+ Type: SHT_DYNSYM+ Flags: 0x0000000000000002+ Addr: 0x00000000000001a8+ Offset: 0x00000000000001a8+ Size: 0x00000000000000f0+ Link: 4+ Info: 1+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000018+ - N: 4+ Name: 29+ Type: SHT_STRTAB+ Flags: 0x0000000000000002+ Addr: 0x0000000000000298+ Offset: 0x0000000000000298+ Size: 0x000000000000005e+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+ - N: 5+ Name: 37+ Type: SHT_EXT 1879048191+ Flags: 0x0000000000000002+ Addr: 0x00000000000002f6+ Offset: 0x00000000000002f6+ Size: 0x0000000000000014+ Link: 3+ Info: 0+ AddrAlign: 0x0000000000000002+ EntSize: 0x0000000000000002+ - N: 6+ Name: 50+ Type: SHT_EXT 1879048189+ Flags: 0x0000000000000002+ Addr: 0x0000000000000310+ Offset: 0x0000000000000310+ Size: 0x0000000000000038+ Link: 4+ Info: 2+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ - N: 7+ Name: 65+ Type: SHT_DYNAMIC+ Flags: 0x0000000000000003+ Addr: 0x0000000000000348+ Offset: 0x0000000000000348+ Size: 0x0000000000000120+ Link: 4+ Info: 0+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000010+ - N: 8+ Name: 74+ Type: SHT_PROGBITS+ Flags: 0x0000000000000003+ Addr: 0x0000000000000468+ Offset: 0x0000000000000468+ Size: 0x0000000000000340+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ - N: 9+ Name: 82+ Type: SHT_NOTE+ Flags: 0x0000000000000002+ Addr: 0x00000000000007a8+ Offset: 0x00000000000007a8+ Size: 0x000000000000003c+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000004+ EntSize: 0x0000000000000000+ - N: 10+ Name: 88+ Type: SHT_PROGBITS+ Flags: 0x0000000000000002+ Addr: 0x00000000000007e4+ Offset: 0x00000000000007e4+ Size: 0x000000000000003c+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000004+ EntSize: 0x0000000000000000+ - N: 11+ Name: 102+ Type: SHT_PROGBITS+ Flags: 0x0000000000000002+ Addr: 0x0000000000000820+ Offset: 0x0000000000000820+ Size: 0x0000000000000148+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000008+ EntSize: 0x0000000000000000+ - N: 12+ Name: 112+ Type: SHT_PROGBITS+ Flags: 0x0000000000000006+ Addr: 0x0000000000000970+ Offset: 0x0000000000000970+ Size: 0x00000000000005ea+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000010+ EntSize: 0x0000000000000000+ - N: 13+ Name: 118+ Type: SHT_PROGBITS+ Flags: 0x0000000000000002+ Addr: 0x0000000000000f5a+ Offset: 0x0000000000000f5a+ Size: 0x000000000000008f+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+ - N: 14+ Name: 135+ Type: SHT_PROGBITS+ Flags: 0x0000000000000006+ Addr: 0x0000000000000fe9+ Offset: 0x0000000000000fe9+ Size: 0x0000000000000022+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+ - N: 15+ Name: 157+ Type: SHT_PROGBITS+ Flags: 0x0000000000000030+ Addr: 0x0000000000000000+ Offset: 0x000000000000100b+ Size: 0x0000000000000024+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000001+ - N: 16+ Name: 1+ Type: SHT_STRTAB+ Flags: 0x0000000000000000+ Addr: 0x0000000000000000+ Offset: 0x000000000000102f+ Size: 0x00000000000000a6+ Link: 0+ Info: 0+ AddrAlign: 0x0000000000000001+ EntSize: 0x0000000000000000+Segments: - N: 0+ Type: PT_LOAD+ Flags: [PF_X,PF_R]+ Offset: 0x0000000000000000+ VirtAddr: 0x0000000000000000+ PhysAddr: 0x0000000000000000+ FileSize: 0x000000000000100b+ MemSize: 0x000000000000100b+ Align: 0x0000000000001000+ - N: 1+ Type: PT_DYNAMIC+ Flags: [PF_R]+ Offset: 0x0000000000000348+ VirtAddr: 0x0000000000000348+ PhysAddr: 0x0000000000000348+ FileSize: 0x0000000000000120+ MemSize: 0x0000000000000120+ Align: 0x0000000000000008+ - N: 2+ Type: PT_NOTE+ Flags: [PF_R]+ Offset: 0x00000000000007a8+ VirtAddr: 0x00000000000007a8+ PhysAddr: 0x00000000000007a8+ FileSize: 0x000000000000003c+ MemSize: 0x000000000000003c+ Align: 0x0000000000000004+ - N: 3+ Type: PT_EXT 1685382480+ Flags: [PF_R]+ Offset: 0x00000000000007e4+ VirtAddr: 0x00000000000007e4+ PhysAddr: 0x00000000000007e4+ FileSize: 0x000000000000003c+ MemSize: 0x000000000000003c+ Align: 0x0000000000000004
+ tests/testdata/orig/vdso.layout.golden view
@@ -0,0 +1,46 @@+┌── 0x00000000 P PT_LOAD [PF_X,PF_R]+│ ┎ 0x00000000 H+│ ┖ 0x0000003f+│ ┎ 0x00000040 PT (4)+│ ┖ 0x0000011f+│ ╓ 0x00000120 S1 ".hash" SHT_HASH [SHF_ALLOC]+│ ╙ 0x0000015b+│ ╓ 0x00000160 S2 ".gnu.hash" SHT_EXT 1879048182 [SHF_ALLOC]+│ ╙ 0x000001a7+│ ╓ 0x000001a8 S3 ".dynsym" SHT_DYNSYM [SHF_ALLOC]+│ ╙ 0x00000297+│ ╓ 0x00000298 S4 ".dynstr" SHT_STRTAB [SHF_ALLOC]+│ ╙ 0x000002f5+│ ╓ 0x000002f6 S5 ".gnu.version" SHT_EXT 1879048191 [SHF_ALLOC]+│ ╙ 0x00000309+│ ╓ 0x00000310 S6 ".gnu.version_d" SHT_EXT 1879048189 [SHF_ALLOC]+│ ╙ 0x00000347+│┌─ 0x00000348 P PT_DYNAMIC [PF_R]+││╓ 0x00000348 S7 ".dynamic" SHT_DYNAMIC [SHF_WRITE,SHF_ALLOC]+││╙ 0x00000467+│└─ 0x00000467+│ ╓ 0x00000468 S8 ".rodata" SHT_PROGBITS [SHF_WRITE,SHF_ALLOC]+│ ╙ 0x000007a7+│┌─ 0x000007a8 P PT_NOTE [PF_R]+││╓ 0x000007a8 S9 ".note" SHT_NOTE [SHF_ALLOC]+││╙ 0x000007e3+│└─ 0x000007e3+│┌─ 0x000007e4 P PT_EXT 1685382480 [PF_R]+││╓ 0x000007e4 S10 ".eh_frame_hdr" SHT_PROGBITS [SHF_ALLOC]+││╙ 0x0000081f+│└─ 0x0000081f+│ ╓ 0x00000820 S11 ".eh_frame" SHT_PROGBITS [SHF_ALLOC]+│ ╙ 0x00000967+│ ╓ 0x00000970 S12 ".text" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+│ ╙ 0x00000f59+│ ╓ 0x00000f5a S13 ".altinstructions" SHT_PROGBITS [SHF_ALLOC]+│ ╙ 0x00000fe8+│ ╓ 0x00000fe9 S14 ".altinstr_replacement" SHT_PROGBITS [SHF_ALLOC,SHF_EXECINSTR]+│ ╙ 0x0000100a+└── 0x0000100a+ ╓ 0x0000100b S15 ".comment" SHT_PROGBITS [SHF_EXT 16,SHF_EXT 32]+ ╙ 0x0000102e+ ╓ 0x0000102f S16 ".shstrtab" SHT_STRTAB []+ ╙ 0x000010d4+ ┎ 0x000010d8 ST (17)+ ┖ 0x00001517
+ tests/testdata/orig/vdso.strtable.golden view
@@ -0,0 +1,16 @@+<>+<.altinstr_replacement>+<.altinstructions>+<.comment>+<.dynamic>+<.dynstr>+<.dynsym>+<.eh_frame>+<.eh_frame_hdr>+<.gnu.hash>+<.gnu.version>+<.gnu.version_d>+<.note>+<.rodata>+<.shstrtab>+<.text>