packages feed

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 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>