diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,8 +1,15 @@
+1.0.2
+=====
+
+- Add documentation to `README.md`
+- examples: Rework `DummyLd`, add an x86 test file.
+- examples: Rework the last sections of the `README_ru.md`
+
 1.0.1
 =====
 
-- Rename Aarch64 -> AArch64
-- Rework examples: fuse `MkObj` into `AsmAArch64`, rewrite `MkExe` as `DummyLd`
+- examples: Rename Aarch64 -> AArch64
+- examples: Fuse `MkObj` into `AsmAArch64`, rewrite `MkExe` as `DummyLd`
 - Implement `elfFindSectionByName`
 - Add test data into the hackage tarball
 
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -2,7 +2,495 @@
 
 > A [Haskell](https://www.haskell.org/) library to parse/serialize
 > Executable and Linkable Format ([ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format))
+> files.
 
+## Parsing the header and table entries
+
+Module
+[`Data.Elf.Headers`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html)
+implements parsing and serialization of the ELF file header and the entries of section and segment tables.
+
+ELF files come in two flavors: 64-bit and 32-bit.
+To differentiate between them type
+[`ElfClass`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:ElfClass)
+is defined:
+
+``` Haskell
+data ElfClass
+    = ELFCLASS32 -- ^ 32-bit ELF format
+    | ELFCLASS64 -- ^ 64-bit ELF format
+    deriving (Eq, Show)
+```
+
+Some fields of the header and table entries have different bitwidth for 64-bit and 32-bit files.
+So the type
+[`WordXX a`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:WordXX)
+was borrowed from the `data-elf` package:
+
+``` Haskell
+-- | @IsElfClass a@ is defined for each constructor of `ElfClass`.
+--   It defines @WordXX a@, which is `Word32` for `ELFCLASS32`
+--   and `Word64` for `ELFCLASS64`.
+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
+```
+
+The header of the ELF file is represented with the type
+[`HeaderXX a`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:HeaderXX):
+
+``` Haskell
+-- | Parsed ELF header
+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
+        }
+```
+
+So we have two types `HeaderXX 'ELFCLASS64` and `HeaderXX 'ELFCLASS32`.
+To be able to work with headers uniformly the type
+[`Header`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:Header)
+was introduced:
+
+``` Haskell
+-- | Sigma type where `ElfClass` defines the type of `HeaderXX`
+type Header = Sigma ElfClass (TyCon1 HeaderXX)
+```
+
+`Header` is a pair.
+The first element is an object of the type `ElfClass` defining the width of the word.
+The second element is `HeaderXX` parametrized with the first element (i. e. Σ-type from
+the languages with dependent types).
+To simulate Σ-types the library
+`singletons`
+([Hackage](https://hackage.haskell.org/package/singletons),
+ ["Introduction to singletons"](https://blog.jle.im/entry/introduction-to-singletons-1.html))
+was used.
+
+`Header` is an instance of the
+[`Binary`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary.html#t:Binary)
+class.
+
+So given a lazy bytestring containing large enough initial part of ELF file one can get the header of
+that file with a function like this:
+
+``` 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
+```
+
+The function
+[`decodeOrFail`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary.html#v:decodeOrFail)
+is defined in the package
+[`binary`](https://hackage.haskell.org/package/binary).
+The function
+[`withElfClass`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#v:withElfClass)
+creates a context with an implicit word width available and looks like
+[`withSingI`](https://hackage.haskell.org/package/singletons-3.0.1/docs/Data-Singletons.html#v:withSingI):
+
+
+``` 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
+```
+
+The module `Data.Elf.Headers` also defines the types
+[`SectionXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:SectionXX),
+[`SegmentXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:SegmentXX) and
+[`SymbolXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:SymbolXX)
+for the elements of section, segment and symbol tables.
+
+## Parsing the whole ELF file
+
+The module
+[`Data.Elf`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html)
+implements parsing and serialization of the whole ELF files.
+To parse ELF file it reads ELF header, section table and segment table and uses that data to create
+a list of elements of the type
+[`ElfXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#t:ElfXX)
+representing the recursive structure of the ELF file.
+It also restores section names from the the string table indexes.
+That results in creating an object of type
+[`Elf`](https://hackage.haskell.org/package/melf-1.0.1/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
+        }
+
+```
+
+Not each object of that type can be serialized.
+
+  * Constructor `ElfSection` still has a section number.
+    It is required as the symbol table and some other structures
+    refer to the sections by theirs indexes.
+    So the section indexes should be consecutive integers starting from 1.
+    Section with index 0 is always empty and is created by the library.
+
+  * There should be a single `ElfHeader`.  It should be the first nonempty node of the tree.
+
+  * If there exists at least one node `ElfSection` then there should exist exactly one
+    node `ElfSectionTable` and exactly one section that has `ElfSectionDataStringTable` as the value
+    of its `esData` field (the string table for the names of sections).
+
+  * If there exists at least one node `ElfSegment` then there should exist exactly one
+    node `ElfSegmentTable`.
+
+Correctly composed ELF object can be serialized with the function
+[`serializeElf`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:serializeElf)
+and parsed with the function
+[`parseElf`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:parseElf):
+
+``` Haskell
+serializeElf :: MonadThrow m => Elf -> m ByteString
+parseElf :: MonadCatch m => ByteString -> m Elf
+```
+
+`ELF` is not an instance of the class `Binary` because
+[`PutM`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary-Put.html#t:PutM)
+is not an instance of the class `MonadFail`.
+
+## Generation of object files
+
+To create machine code that is used in the examples a pair of modules were created.
+The module
+[`AsmAArch64`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/examples/AsmAarch64.hs)
+provides a DSL embedded in Haskell.
+This DSL is a kind of assembler language for the AArch64 platform.
+It exports some primitives to generate machine instructions and organize machine code.
+It also exports function `assemble` that consumes the monad composed of those primitives and
+produces an object of the type `Elf`:
+
+``` Haskell
+assemble :: MonadCatch m => StateT CodeState m () -> m Elf
+```
+
+The idea was inspired by the article
+([Stephen Diehl "Monads to Machine Code"](https://www.stephendiehl.com/posts/monads_machine_code.html)).
+Detailed description of this module is available in russian:
+[README_ru.md](https://github.com/aleksey-makarov/melf/blob/v1.0.2/examples/README_ru.md).
+
+The module
+[`HelloWorld`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/examples/HelloWorld.hs)
+uses primitives from `AsmAArch64` to compose relocatable executable code that uses system calls
+to output a "Hello World!" message into standard output and exit:
+
+``` Haskell
+helloWorld :: MonadCatch m => StateT CodeState m ()
+```
+
+Function `assemble` uses the `melf` library to generate an object file:
+
+``` Haskell
+    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
+        ]
+```
+
+It runs the `State` monad that was passed as an argument.
+As a result the final state of `CodeState` includes all the data neсessary to produce ELF file, in
+particular:
+
+  * `txt` refers to the content of the `.text` section,
+  * `symbolTableData` refers to the content of the symbol table section,
+  * `stringTableData` refers to the content of the string table section linked to the symbol table.
+
+Names with `SecN` suffixes (`textSecN`, `shstrtabSecN`, `symtabSecN`, `strtabSecN`)
+are predefined section numbers that conform to the conditions stated above.
+
+For the sake of simplicity external symbol resolution and data section allocation were not implemented.
+It requires implementation of relocation tables.  On the other hand, the resulting code
+is position-independent.
+
+Use this module to produce object file and try to link it:
+
+```
+[nix-shell:examples]$ ghci 
+GHCi, version 8.10.7: https://www.haskell.org/ghc/  :? for help
+Prelude> :l AsmAArch64.hs HelloWorld.hs 
+[1 of 2] Compiling AsmAArch64       ( AsmAArch64.hs, interpreted )
+[2 of 2] Compiling HelloWorld       ( HelloWorld.hs, interpreted )
+Ok, two modules loaded.
+*AsmAArch64> import HelloWorld
+*AsmAArch64 HelloWorld> elf <- assemble helloWorld
+*AsmAArch64 HelloWorld> bs <- serializeElf elf
+*AsmAArch64 HelloWorld> BSL.writeFile "helloWorld.o" bs
+*AsmAArch64 HelloWorld> 
+Leaving GHCi.
+
+[nix-shell:examples]$ aarch64-unknown-linux-gnu-gcc -nostdlib helloWorld.o -o helloWorld
+
+[nix-shell:examples]$ 
+```
+
+The linker accepted the object file.  Try to run the result:
+
+```
+[nix-shell:examples]$ qemu-aarch64 helloWorld
+Hello World!
+
+[nix-shell:examples]$ 
+```
+
+It works.
+
+## Generation of executable files
+
+The module
+[`DummyLd`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/examples/DummyLd.hs)
+uses the section `.text` of object file to create an executable file.
+Code relocation and symbol resolution is not implemented so that procedure works only
+for position-independent code that does not refer to external translation units,
+for example, it works with the code described above.
+
+Function `dummyLd` consumes an object of the type `Elf` and finds a section `.text`
+(using [`elfFindSectionByName`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:elfFindSectionByName))
+and header
+(using [`elfFindHeader`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:elfFindHeader))
+in it.
+Then the header type is changed to `ET_EXEC`, the address of the first executable instruction is specified and
+a loadable segment containing the header and the content of `.text` is formed:
+
+``` Haskell
+data MachineConfig (a :: ElfClass)
+    = MachineConfig
+        { mcAddress :: WordXX a -- ^ Virtual address of the executable segment
+        , mcAlign   :: WordXX a -- ^ Required alignment of the executable segment
+                                --   in physical memory (depends on max page size)
+        }
+
+getMachineConfig :: (IsElfClass a, MonadThrow m) => ElfMachine -> m (MachineConfig a)
+getMachineConfig EM_AARCH64 = return $ MachineConfig 0x400000 0x10000
+getMachineConfig EM_X86_64  = return $ MachineConfig 0x400000 0x1000
+getMachineConfig _          = $chainedError "could not find machine config for this arch"
+
+dummyLd' :: forall a m . (MonadThrow m, IsElfClass a) => ElfList a -> m (ElfList a)
+dummyLd' (ElfList es) = do
+
+    txtSection <- elfFindSectionByName es ".text"
+    txtSectionData <- case txtSection of
+        ElfSection { esData = ElfSectionData textData } -> return textData
+        _ -> $chainedError "could not find correct \".text\" section"
+
+    header <- elfFindHeader es
+    case header of
+        ElfHeader { .. } -> do
+            MachineConfig { .. } <- getMachineConfig ehMachine
+            return $ ElfList
+                [ ElfSegment
+                    { epType       = PT_LOAD
+                    , epFlags      = PF_X .|. PF_R
+                    , epVirtAddr   = mcAddress
+                    , epPhysAddr   = mcAddress
+                    , epAddMemSize = 0
+                    , epAlign      = mcAlign
+                    , epData       =
+                        [ ElfHeader
+                            { ehType  = ET_EXEC
+                            , ehEntry = mcAddress + headerSize (fromSing $ sing @a)
+                            , ..
+                            }
+                        , ElfRawData
+                            { edData = txtSectionData
+                            }
+                        ]
+                    }
+                , ElfSegmentTable
+                ]
+        _ -> $chainedError "could not find ELF header"
+
+-- | @dummyLd@ places the content of ".text" section of the input ELF
+-- into the loadable segment of the resulting ELF.
+-- This could work if there are no relocations or references to external symbols.
+dummyLd :: MonadThrow m => Elf -> m Elf
+dummyLd (c :&: l) = (c :&:) <$> withElfClass c dummyLd' l
+```
+
+Try to use this code to produce executable file without GNU linker:
+
+```
+[nix-shell:examples]$ ghci
+GHCi, version 8.10.7: https://www.haskell.org/ghc/  :? for help
+Prelude> :l DummyLd.hs
+[1 of 1] Compiling DummyLd          ( DummyLd.hs, interpreted )
+Ok, one module loaded.
+*DummyLd> import Data.ByteString.Lazy as BSL
+*DummyLd BSL> i <- BSL.readFile "helloWorld.o"
+*DummyLd BSL> elf <- parseElf i
+*DummyLd BSL> elf' <- dummyLd elf
+*DummyLd BSL> o <- serializeElf elf'
+*DummyLd BSL> BSL.writeFile "helloWorld2" o
+*DummyLd BSL> 
+Leaving GHCi.
+
+[nix-shell:examples]$ chmod +x helloWorld2
+
+[nix-shell:examples]$ qemu-aarch64 helloWorld2
+Hello World!
+
+[nix-shell:examples]$ 
+```
+
+It works.
+
 ## Related work
 
 - [elf](https://github.com/wangbj/elf)
@@ -18,7 +506,7 @@
 ## Tests
 
 Test data is committed with [git-lfs](https://git-lfs.github.com/).
-To run tests, issue this command in `nix-shell`: `cabal new-test --test-show-details=direct`
+Only testdata/orig/* tests are included to hackage distributive to keep the tarball size small.
 
 ## License
 
diff --git a/examples/AsmAArch64.hs b/examples/AsmAArch64.hs
--- a/examples/AsmAArch64.hs
+++ b/examples/AsmAArch64.hs
@@ -15,7 +15,7 @@
 module AsmAArch64
     ( CodeState
     , Register
-    , RelativeRef
+    , Label
     , adr
     , b
     , mov
@@ -56,8 +56,8 @@
 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
+data Label = CodeRef !CodeOffset
+           | PoolRef !CodeOffset
 
 -- Args:
 -- Offset of the instruction
@@ -68,7 +68,7 @@
     { offsetInPool    :: CodeOffset
     , poolReversed    :: [Builder]
     , codeReversed    :: [InstructionGen]
-    , symbolsRefersed :: [(String, RelativeRef)]
+    , symbolsRefersed :: [(String, Label)]
     }
 
 emit' :: MonadState CodeState m => InstructionGen -> m ()
@@ -80,7 +80,7 @@
 emit :: MonadState CodeState m => Instruction -> m ()
 emit i = emit' $ \ _ _ -> Right i
 
-emitPool :: MonadState CodeState m => Word -> ByteString -> m RelativeRef
+emitPool :: MonadState CodeState m => Word -> ByteString -> m Label
 emitPool a bs = state f where
     f CodeState {..} =
         let
@@ -94,7 +94,7 @@
                         }
             )
 
-label :: MonadState CodeState m => m RelativeRef
+label :: MonadState CodeState m => m Label
 label = gets (CodeRef . (* instructionSize) . fromIntegral . P.length . codeReversed)
 
 x0, x1, x2, x8 :: Register 'X
@@ -125,7 +125,7 @@
     SW -> 0
 
 -- | C6.2.10 ADR
-adr :: MonadState CodeState m => Register 'X -> RelativeRef -> m ()
+adr :: MonadState CodeState m => Register 'X -> Label -> m ()
 adr (R n) rr =  emit' f where
 
     offsetToImm :: CodeOffset -> Either String Word32
@@ -147,7 +147,7 @@
                             .|. n
 
 -- | C6.2.26 B
-b :: MonadState CodeState m => RelativeRef -> m ()
+b :: MonadState CodeState m => Label -> m ()
 b rr = emit' f where
 
     offsetToImm26 :: CodeOffset -> Either String Word32
@@ -176,12 +176,12 @@
         h = w .&. m
     in if w >= 0 then h == 0 else h == m
 
-findOffset :: CodeOffset -> RelativeRef -> CodeOffset
+findOffset :: CodeOffset -> Label -> 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 :: (MonadState CodeState m, SingI w) => Register w -> Label -> m ()
 ldr r@(R n) rr = emit' f where
 
     offsetToImm19 :: CodeOffset -> Either String Word32
@@ -202,10 +202,10 @@
 svc :: MonadState CodeState m => Word16 -> m ()
 svc imm = emit $ 0xd4000001 .|. (fromIntegral imm `shift` 5)
 
-ascii :: MonadState CodeState m => String -> m RelativeRef
+ascii :: MonadState CodeState m => String -> m Label
 ascii s = emitPool 1 $ BSLC.pack s
 
-exportSymbol :: MonadState CodeState m => String -> RelativeRef -> m ()
+exportSymbol :: MonadState CodeState m => String -> Label -> m ()
 exportSymbol s r = modify f where
     f (CodeState {..}) = CodeState { symbolsRefersed = (s, r) : symbolsRefersed
                                    , ..
@@ -248,7 +248,7 @@
     -- resolve symbolTable
 
     let
-        ff :: (String, RelativeRef) -> ElfSymbolXX 'ELFCLASS64
+        ff :: (String, Label) -> ElfSymbolXX 'ELFCLASS64
         ff (s, r) =
             let
                 steName  = s
diff --git a/examples/DummyLd.hs b/examples/DummyLd.hs
--- a/examples/DummyLd.hs
+++ b/examples/DummyLd.hs
@@ -1,14 +1,16 @@
 {-# LANGUAGE DataKinds #-}
+{-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE TypeApplications #-}
 {-# 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
 import Data.Singletons.Sigma
 
 import Data.Elf
@@ -16,48 +18,55 @@
 import Data.Elf.Headers
 import Control.Exception.ChainedException
 
-addr :: Word64
-addr = 0x400000
+data MachineConfig (a :: ElfClass)
+    = MachineConfig
+        { mcAddress :: WordXX a -- ^ Virtual address of the executable segment
+        , mcAlign   :: WordXX a -- ^ Required alignment of the executable segment
+                                --   in physical memory (depends on max page size)
+        }
 
-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
-                ]
-            }
+getMachineConfig :: (IsElfClass a, MonadThrow m) => ElfMachine -> m (MachineConfig a)
+getMachineConfig EM_AARCH64 = return $ MachineConfig 0x400000 0x10000
+getMachineConfig EM_X86_64  = return $ MachineConfig 0x400000 0x1000
+getMachineConfig _          = $chainedError "could not find machine config for this arch"
 
-dummyLd' :: MonadThrow m => ElfList 'ELFCLASS64 -> m (ElfList 'ELFCLASS64)
+dummyLd' :: forall a m . (MonadThrow m, IsElfClass a) => ElfList a -> m (ElfList a)
 dummyLd' (ElfList es) = do
 
     txtSection <- elfFindSectionByName es ".text"
-
-    case txtSection of
-        ElfSection{esData = ElfSectionData textData} -> mkExe textData
+    txtSectionData <- case txtSection of
+        ElfSection { esData = ElfSectionData textData } -> return 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
+    header <- elfFindHeader es
+    case header of
+        ElfHeader { .. } -> do
+            MachineConfig { .. } <- getMachineConfig ehMachine
+            return $ ElfList
+                [ ElfSegment
+                    { epType       = PT_LOAD
+                    , epFlags      = PF_X .|. PF_R
+                    , epVirtAddr   = mcAddress
+                    , epPhysAddr   = mcAddress
+                    , epAddMemSize = 0
+                    , epAlign      = mcAlign
+                    , epData       =
+                        [ ElfHeader
+                            { ehType  = ET_EXEC
+                            , ehEntry = mcAddress + headerSize (fromSing $ sing @a)
+                            , ..
+                            }
+                        , ElfRawData
+                            { edData = txtSectionData
+                            }
+                        ]
+                    }
+                , ElfSegmentTable
+                ]
+        _ -> $chainedError "could not find ELF header"
+
+-- | @dummyLd@ places the content of ".text" section of the input ELF
+-- into the loadable segment of the resulting ELF.
+-- This 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
+dummyLd (c :&: l) = (c :&:) <$> withElfClass c dummyLd' l
diff --git a/examples/ForwardLabel.hs b/examples/ForwardLabel.hs
--- a/examples/ForwardLabel.hs
+++ b/examples/ForwardLabel.hs
@@ -8,6 +8,7 @@
 import Control.Monad.Catch
 import Control.Monad.Fix
 import Control.Monad.State
+import Data.Word
 
 import AsmAArch64
 
@@ -17,6 +18,11 @@
 bad :: String
 bad = "bad\n"
 
+-- | syscalls
+sysExit, sysWrite :: Word16
+sysWrite = 64
+sysExit = 93
+
 forwardLabel :: (MonadCatch m, MonadFix m) => StateT CodeState m ()
 forwardLabel = mdo
 
@@ -37,9 +43,9 @@
 
     skipBad <- label
 
-    mov x8 64
+    mov x8 sysWrite
     svc 0
 
     mov x0 0
-    mov x8 93
+    mov x8 sysExit
     svc 0
diff --git a/examples/HelloWorld.hs b/examples/HelloWorld.hs
--- a/examples/HelloWorld.hs
+++ b/examples/HelloWorld.hs
@@ -13,9 +13,10 @@
 msg :: String
 msg = "Hello World!\n"
 
-sys_exit, sys_write :: Word16
-sys_write = 64
-sys_exit = 93
+-- | syscalls
+sysExit, sysWrite :: Word16
+sysWrite = 64
+sysExit = 93
 
 helloWorld :: MonadCatch m => StateT CodeState m ()
 helloWorld = do
@@ -26,9 +27,9 @@
     helloString <- ascii msg
     adr x1 helloString
     mov x2 $ fromIntegral $ P.length msg
-    mov x8 sys_write
+    mov x8 sysWrite
     svc 0
 
     mov x0 0
-    mov x8 sys_exit
+    mov x8 sysExit
     svc 0
diff --git a/examples/README_ru.md b/examples/README_ru.md
--- a/examples/README_ru.md
+++ b/examples/README_ru.md
@@ -1,6 +1,6 @@
 ---
 title: Работа с файлами формата ELF из Хаскела
-date: November 17, 2021
+date: December 21, 2021
 ---
 
 Работа с файлами формата ELF -- популярная тема на Хабре.
@@ -13,37 +13,40 @@
 Эти библиотеки работают только с заголовками и элементами таблиц и не дают возможности
 сгенерировать объектный файл.
 
-Я написал библиотеку для работы с файлами формата ELF на Хаскеле
-([GitHub](https://github.com/aleksey-makarov/melf),
- [Hackage](https://hackage.haskell.org/package/melf))
-и хочу показать как её использовать.
+Библиотека `melf`
+([GitHub](https://github.com/aleksey-makarov/melf), [Hackage](https://hackage.haskell.org/package/melf))
+даёт возможность полностью разобрать файл ELF и сгенерировать такой файл по несложной структуре данных.
+Ниже даются примеры её использования.
 
 ## Внутреннее устройство ELF
 
-Первые несколько байт файла занимает заголовок ELF.
-В нём, в частности, указано, где в файле расположены таблица секций и таблица сегментов.
 
-Сегменты и секции -- непрерывные участки файла.
-Сегменты описывают, что нужно поместить в память при загрузки программы,
-а секции я бы описал как неделимые результаты работы
-компилятора.
+В файле формата ELF последовательно размещены заголовок файла,
+секции, сегменты, таблица секций, таблица сегментов.
+Сегменты в свою очередь скомпанованы из таких же элементов.
+Порядок этих элементов произвольный, за исключением того, что заголовок файла всегда размещается в начале файла,
+а таблиц секций и таблиц сегментов может быть не более одной.
+Каждый такой участок выровнен в файле, например, сегменты обычно выравниваются на размер страницы,
+а секции с данными -- на размер слова.
+
+В заголовке описано, где располагаются таблица секций и таблица сегментов,
+которые в свою очередь описывают, где располагаются секции и сегменты.
+
+Сегменты указывают, что нужно поместить в память при загрузки программы,
+а секции я бы определил как неделимые результаты работы компилятора.
 В секциях размещены исполняемый код, таблицы символов, инициализированные данные.
+Линковщик объединяет секции из различных единиц трансляции в сегменты.
 
-Файл формата ELF можно представлять как список деревьев.
-Деревьями могуть быть секции, сегменты, заголовок файла, таблица секций, таблица сегментов.
-Поддеревья могут содержаться только в сегментах.
-Узлы дерева выравниваются в файле, например, сегменты обычно выравниваются на размер страницы,
-а секции с данными -- на размер слова.
 Вполне валидным может быть файл, где сегмент содержит данные, не размеченные как какая-либо секция.
 
 ## Базовый уровень
 
 В модуле
-[`Data.Elf.Headers`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html)
+[`Data.Elf.Headers`](https://hackage.haskell.org/package/melf-1.0.1/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)
+[`ElfClass`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:ElfClass)
 
 ``` Haskell
 data ElfClass
@@ -54,14 +57,13 @@
 
 Некоторые поля заголовка и элементов таблиц секций и сегментов имеют разную ширину в битах, зависящую от
 `ElfClass`, поэтому нужен тип
-[`WordXX a`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:WordXX),
+[`WordXX a`](https://hackage.haskell.org/package/melf-1.0.1/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)
@@ -90,11 +92,10 @@
 ```
 
 Заголовок файла ELF представлен с помощью типа
-[`HeaderXX a`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:HeaderXX):
+[`HeaderXX a`](https://hackage.haskell.org/package/melf-1.0.1/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)
@@ -114,9 +115,8 @@
         }
 ```
 
-Но это разные типы для 64- и 32-битных форматов.
 Для однообразной работы с форматами с разной шириной слова определён тип
-[`Header`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf-Headers.html#t:Header):
+[`Header`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:Header):
 
 ``` Haskell
 -- | Sigma type where `ElfClass` defines the type of `HeaderXX`
@@ -124,14 +124,13 @@
 ```
 
 `Header` это пара, первый элемент которой -- объект типа `ElfClass`, определяющий ширину слова,
-второй -- `HeaderXX`, параметризованный первым элементом ($\Sigma$-тип из языков с зависимыми типами).
-Для симуляции $\Sigma$-типов использована библиотека `singletons`
+второй -- `HeaderXX`, параметризованный первым элементом (Σ-тип из языков с зависимыми типами).
+Для симуляции Σ-типов использована библиотека `singletons`
 ([Hackage](https://hackage.haskell.org/package/singletons),
  ["Introduction to singletons"](https://blog.jle.im/entry/introduction-to-singletons-1.html)).
 
-Для `Header` определён экземпляр класса
+`Header` является экземпляром класса
 [`Binary`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary.html#t:Binary).
-
 Таким образом, имея ленивую строку байт, содержащую достаточно длинный начальный отрезок файла ELF,
 можно получить заголовок этого файла, например, следующей функцией:
 
@@ -148,9 +147,10 @@
 Здесь
 [`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):
+[`withElfClass`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#v:withElfClass)
+делает явный аргумент, определяющий размер слова, неявным (constraint).
+Функция похожа на
+[`withSingI`](https://hackage.haskell.org/package/singletons-3.0.1/docs/Data-Singletons.html#v:withSingI):
 
 ``` Haskell
 -- | Convenience function for creating a
@@ -161,23 +161,23 @@
 ```
 
 В `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)
+[`SectionXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:SectionXX),
+[`SegmentXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:SegmentXX) и
+[`SymbolXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf-Headers.html#t:SymbolXX)
 для элементов таблиц секций, сегментов и символов.
 
 ## Верхний уровень
 
 В модуле
-[`Data.Elf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html)
+[`Data.Elf`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html)
 реализованы полные разбор и сериализация файлов формата ELF.
 Чтобы разобрать такой файл читаются заголовок ELF, таблицa секций и таблица сегментов и
 на основании этой информации создаётся список элементов типа
-[`ElfXX`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#t:ElfXX),
+[`ElfXX`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#t:ElfXX),
 отображающий рекурсивную
-структуру файла ELF.  Кроме восстановления структуры в процессе разбора, например, по номерам
+структуру файла ELF.  Кроме восстановления структуры в процессе разбора, по номерам
 секций восстанавливаются их имена.  В результате получается объект типа
-[`Elf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#t:Elf):
+[`Elf`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#t:Elf):
 
 ``` Haskell
 -- | `Elf` is a forrest of trees of type `ElfXX`.
@@ -246,10 +246,10 @@
 Не каждый объект такого типа может быть сериализован.
 
   * В конструкторе `ElfSection`
-остался номер секции.  Он нужен, так как таблица символов и некоторые другие структуры
-ссылаются на секци по их номерам.  Поэтому при построении объекта такого типа нужно убедиться,
-что секции пронумерованы корректно, т. е. последовательными целыми от 1 до количества секций.
-Секция с номером 0 всегда пустая и она добавляется автоматически.
+    остался номер секции.  Он нужен, так как таблица символов и некоторые другие структуры
+    ссылаются на секци по их номерам.  Поэтому при построении объекта такого типа нужно убедиться,
+    что секции пронумерованы корректно, т. е. последовательными целыми числами от 1 до количества секций.
+    Секция с номером 0 всегда пустая, она добавляется автоматически.
 
   * В структуре должен быть единственный `ElfHeader`, он должен быть самым первым непустым
     узлом в дереве.
@@ -257,12 +257,12 @@
   * Если есть хотя бы один узел `ElfSection`, то должен присутсвовать в точности один узел `ElfSectionTable`
     и в точности одна секция, поле `esData` которой равно `ElfSectionDataStringTable` (таблица строк для имён секций).
 
-  * Если есть хотя бы один узел с конструктором `ElfSegment`, то должен присутсвовать в точности один узел `ElfSegmentTable`.
+  * Если есть хотя бы один узел `ElfSegment`, то должен присутсвовать в точности один узел `ElfSegmentTable`.
 
 Корректно сформированный объект можно сериализовать с помощью функции
-[`serializeElf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#v:serializeElf)
+[`serializeElf`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:serializeElf)
 и разобрать с помощью функции
-[`parseElf`](https://hackage.haskell.org/package/melf-1.0.0/docs/Data-Elf.html#v:parseElf):
+[`parseElf`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:parseElf):
 
 ``` Haskell
 serializeElf :: MonadThrow m => Elf -> m ByteString
@@ -270,52 +270,51 @@
 ```
 
 Экземпляр класса `Binary` для `ELF` не определён, так как
-[`Put`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary.html#t:Put)
+[`PutM`](https://hackage.haskell.org/package/binary-0.10.0.0/docs/Data-Binary-Put.html#t:PutM)
 не является экземпляром класса `MonadFail`.
 
 ## Ассемблер как EDSL для Хаскела
 
 Для использования в демонстрационных приложениях написан модуль, 
 генерирующий машинный код для AArch64
-(файл [`AsmAarch64.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/AsmAarch64.hs)).
+(файл [`AsmAArch64.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/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)]
+    , symbolsRefersed :: [(String, Label)]
     }
 ```
 
-Для создания меток и ссылок на данные в массиве литералов введён тип `RelativeRef`
+`CodeState` содержит размер массива литералов, сам массив литералов,
+массив машинных кодов и массив символов.
 
+Массив литералов (literal pools) это участок секции в которой расположен
+исполняемый код, используемый для хранения константных данных.
+К таким данным легко обращаться с помощью команд,
+вычисляющих адрес данных с использованием счётчика команд.
+
+Для создания меток и ссылок на данные в массиве литералов введён тип `Label`
+
 ``` Haskell
 newtype CodeOffset  = CodeOffset  { getCodeOffset  :: Int64 }
     deriving (Eq, Show, Ord, Num, Enum, Real, Integral,
     Bits, FiniteBits)
 
-data RelativeRef = CodeRef CodeOffset
-                 | PoolRef CodeOffset
+data Label = CodeRef CodeOffset
+           | PoolRef CodeOffset
 ```
 
 Конструктор `CodeRef` используется для ссылки на код (для создания меток):
 
 ``` Haskell
-label :: MonadState CodeState m => m RelativeRef
+label :: MonadState CodeState m => m Label
 label = gets (CodeRef . (* instructionSize)
                       . fromIntegral
                       . P.length
@@ -323,8 +322,9 @@
 ```
 
 Конструктор `PoolRef` хранит смещение данных от начала массива литералов.
+Он используется для создания `CodeOffset` в функции `emitPool` (см. ниже).
 
-Фактически в массиве машинных кодов хранятся функции для генерации машинного кода
+В массиве машинных кодов хранятся функции для генерации машинного кода
 из смещения команды от начала секции и смещения массива литералов (которое будет
 известно только после обработки всех ассемблерных команд, так как массив литералов
 располагается после кода):
@@ -334,7 +334,7 @@
                       CodeOffset -> Either String Instruction
 ```
 
-Для добавления в массив машинных кодов используется функция `emit'`:
+Для добавления функций в массив машинных кодов используется функция `emit'`:
 
 ```Haskell
 emit' :: MonadState CodeState m => InstructionGen -> m ()
@@ -356,7 +356,7 @@
 svc imm = emit $ 0xd4000001 .|. (fromIntegral imm `shift` 5)
 ```
 
-Как и многие другие команды архитектуры AArch64, команда `mov` может работать с регистрами
+Многие команды архитектуры AArch64 могут работать с регистрами
 как с 64-битными или как с 32-битными значениями.
 Для указания разрядности регистров для них используются разные имена:
 `x0`, `x1`... -- для 64-битных, `w0`, `w1`... -- для 32-битных.
@@ -392,7 +392,7 @@
 -- | C6.2.10 ADR
 adr :: MonadState CodeState m =>
                   Register 'X ->
-                  RelativeRef -> m ()
+                  Label -> m ()
 ```
 
 Для добавления данных в массив литералов используется функция `emitPool`:
@@ -400,7 +400,7 @@
 ``` Haskell
 emitPool :: MonadState CodeState m =>
                               Word ->
-                        ByteString -> m RelativeRef
+                        ByteString -> m Label
 ```
 
 Здесь первый аргумент -- необходимое выравнивание, второй -- данные, которые нужно
@@ -411,60 +411,32 @@
 С помощью этой функции можно, например, реализовать аналог ассемблерной директивы `.ascii`:
 
 ``` Haskell
-ascii :: MonadState CodeState m => String -> m RelativeRef
+ascii :: MonadState CodeState m => String -> m Label
 ascii s = emitPool 1 $ BSLC.pack s
 ```
 
-Кроме того, есть массив символов.  Символы создаются из меток:
+Символы создаются из меток:
 
 ``` Haskell
-exportSymbol :: MonadState CodeState m => String -> RelativeRef -> m ()
+exportSymbol :: MonadState CodeState m => String -> Label -> 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)):
+Используя таким образом определённые примитивы можно написать код
+для вывода "Hello World!" на встроенном в Хаскел DSL
+([файл `HelloWorld.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/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
+-- | syscalls
+sysExit, sysWrite :: Word16
+sysWrite = 64
+sysExit = 93
 
 helloWorld :: MonadCatch m => StateT CodeState m ()
 helloWorld = do
@@ -475,52 +447,36 @@
     helloString <- ascii msg
     adr x1 helloString
     mov x2 $ fromIntegral $ P.length msg
-    mov x8 sys_write
+    mov x8 sysWrite
     svc 0
 
     mov x0 0
-    mov x8 sys_exit
+    mov x8 sysExit
     svc 0
 ```
 Если нужно сослаться на метку, сформированную ниже по коду, нужно работать в монаде `MonadFix`
 и использовать ключевое слово `mdo` вместо `do`
-(см. файл [`ForwardLabel.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/ForwardLabel.hs)).
+(см. файл [`ForwardLabel.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/examples/ForwardLabel.hs)).
 
 ## Генерация объектных файлов
 
-Используем библиотеку `melf` для генерации объектных файлов
-([файл `MkObj.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/MkObj.hs)):
+Функция `assemble`
+(см. [`AsmAArch64.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/examples/AsmAArch64.hs))
+транслирует код на встроенном в Хаскел ассемблере в машинные коды и возвращает объект типа `Elf`:
 
 ``` 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
+assemble :: MonadCatch m => StateT CodeState m () -> m Elf
+```
 
-    (txt, symbolTable) <- assemble textSecN m
-    (symbolTableData, stringTableData) <- serializeSymbolTable ELFDATA2LSB symbolTable
+Она запускает переданную в качестве аргумента монаду `State`, представляющую ассемблерный код.
+Конечное состояние этой монады содержит всю информацию о содержимом секции, которая будет содержать код
+(секция с именем `.text`), и таблицы символов,
+a этого достаточно чтобы сгенерировать объектный файл.
+На содержимое секции `.text` ссылается имя `txt`,
+на содержимое таблицы символов -- имя `symbolTableData`,
+на содержимое таблицы строк, связанной с таблицей символов -- имя `stringTableData`:
 
+``` Haskell
     return $ SELFCLASS64 :&: ElfList
         [ ElfHeader
             { ehData       = ELFDATA2LSB
@@ -583,27 +539,31 @@
         ]
 ```
 
+Здесь имена с суффиксом `SecN` (`textSecN`, `shstrtabSecN`, `symtabSecN`, `strtabSecN`) -- предопределённые
+номера секций, удовлетворяющие сформулированным выше условиям.
+
+Для простоты не реализовано обращение ко внешним символам и размещение данных в
+отдельных секциях.
+Всё это требует реализации таблиц перемещений, с другой стороны, сгенерированный код
+получается позиционно-независимым.
+
 Сгенерируем с помощью этого модуля объектный файл и попробуем его слинковать:
 
 ```
 [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> 
+GHCi, version 8.10.7: https://www.haskell.org/ghc/  :? for help
+Prelude> :l AsmAArch64.hs HelloWorld.hs 
+[1 of 2] Compiling AsmAArch64       ( AsmAArch64.hs, interpreted )
+[2 of 2] Compiling HelloWorld       ( HelloWorld.hs, interpreted )
+Ok, two modules loaded.
+*AsmAArch64> import HelloWorld
+*AsmAArch64 HelloWorld> elf <- assemble helloWorld
+*AsmAArch64 HelloWorld> bs <- serializeElf elf
+*AsmAArch64 HelloWorld> BSL.writeFile "helloWorld.o" bs
+*AsmAArch64 HelloWorld> 
 Leaving GHCi.
 
-[nix-shell:examples]$ aarch64-unknown-linux-gnu-gcc -nostdlib hello.o -o hello 
+[nix-shell:examples]$ aarch64-unknown-linux-gnu-gcc -nostdlib helloWorld.o -o helloWorld
 
 [nix-shell:examples]$ 
 ```
@@ -612,7 +572,7 @@
 Попробуем запустить результат:
 
 ```
-[nix-shell:examples]$ qemu-aarch64 hello
+[nix-shell:examples]$ qemu-aarch64 helloWorld
 Hello World!
 
 [nix-shell:examples]$ 
@@ -622,85 +582,102 @@
 
 ## Генерация исполняемых файлов
 
-Так как сгенерированный код для распечатки "Hello World!" является позиционно-независимым
-и не ссылается на другие секции, то его можно без изменений использовать для получения
-исполняемого файла
-([файл `MkExe.hs`](https://github.com/aleksey-makarov/melf/blob/v1.0.0/examples/MkExe.hs)):
+Код из модуля
+[`DummyLd`](https://github.com/aleksey-makarov/melf/blob/v1.0.2/examples/DummyLd.hs)
+использует секцию `.text` объектного файла для того чтобы создать исполняемый файл.
+Перемещение кода и разрешение символов не реализовано, поэтому такая процедура сработает только
+с позиционно-независимым кодом, не ссылающимся на посторонние единицы трансляции,
+например, с кодом, который описан в предыдущем разделе.
 
-``` Haskell
-module MkExe (mkExe) where
+Функция `dummyLd` принимает объект типа `Elf`, ищет в нём секцию `.text`
+(функцией [`elfFindSectionByName`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:elfFindSectionByName))
+и заголовок ELF
+(функцией [`elfFindHeader`](https://hackage.haskell.org/package/melf-1.0.1/docs/Data-Elf.html#v:elfFindHeader)).
+Тип заголовка меняется на `ET_EXEC`, прописывается адрес, по которому будет располагаться
+первая инструкция кода и формируется сегмент, в который помещается заголовок и содежимое `.text`:
 
-import Control.Monad.Catch
-import Control.Monad.State
-import Data.Bits
-import Data.Word
-import Data.Singletons.Sigma
+``` Haskell
+data MachineConfig (a :: ElfClass)
+    = MachineConfig
+        { mcAddress :: WordXX a -- ^ Virtual address of the executable segment
+        , mcAlign   :: WordXX a -- ^ Required alignment of the executable segment
+                                --   in physical memory (depends on max page size)
+        }
 
-import Data.Elf
-import Data.Elf.Constants
-import Data.Elf.Headers
+getMachineConfig :: (IsElfClass a, MonadThrow m) => ElfMachine -> m (MachineConfig a)
+getMachineConfig EM_AARCH64 = return $ MachineConfig 0x400000 0x10000
+getMachineConfig EM_X86_64  = return $ MachineConfig 0x400000 0x1000
+getMachineConfig _          = $chainedError "could not find machine config for this arch"
 
-import AsmAarch64
+dummyLd' :: forall a m . (MonadThrow m, IsElfClass a) => ElfList a -> m (ElfList a)
+dummyLd' (ElfList es) = do
 
-addr :: Word64
-addr = 0x400000
+    txtSection <- elfFindSectionByName es ".text"
+    txtSectionData <- case txtSection of
+        ElfSection { esData = ElfSectionData textData } -> return textData
+        _ -> $chainedError "could not find correct \".text\" section"
 
-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
+    header <- elfFindHeader es
+    case header of
+        ElfHeader { .. } -> do
+            MachineConfig { .. } <- getMachineConfig ehMachine
+            return $ ElfList
+                [ ElfSegment
+                    { epType       = PT_LOAD
+                    , epFlags      = PF_X .|. PF_R
+                    , epVirtAddr   = mcAddress
+                    , epPhysAddr   = mcAddress
+                    , epAddMemSize = 0
+                    , epAlign      = mcAlign
+                    , epData       =
+                        [ ElfHeader
+                            { ehType  = ET_EXEC
+                            , ehEntry = mcAddress + headerSize (fromSing $ sing @a)
+                            , ..
+                            }
+                        , ElfRawData
+                            { edData = txtSectionData
+                            }
+                        ]
                     }
                 , ElfSegmentTable
                 ]
-            }
-    return $ SELFCLASS64 :&: ElfList [ segment ]
+        _ -> $chainedError "could not find ELF header"
+
+-- | @dummyLd@ places the content of ".text" section of the input ELF
+-- into the loadable segment of the resulting ELF.
+-- This could work if there are no relocations or references to external symbols.
+dummyLd :: MonadThrow m => Elf -> m Elf
+dummyLd (c :&: l) = (c :&:) <$> withElfClass c dummyLd' l
 ```
 
-Попробуем его сгенерировать и запустить:
+Попробуем использовать этот код для получения исполняемого файла без участия линковщика GNU:
 
 ```
-[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> 
+[nix-shell:examples]$ ghci
+GHCi, version 8.10.7: https://www.haskell.org/ghc/  :? for help
+Prelude> :l DummyLd.hs
+[1 of 1] Compiling DummyLd          ( DummyLd.hs, interpreted )
+Ok, one module loaded.
+*DummyLd> import Data.ByteString.Lazy as BSL
+*DummyLd BSL> i <- BSL.readFile "helloWorld.o"
+*DummyLd BSL> elf <- parseElf i
+*DummyLd BSL> elf' <- dummyLd elf
+*DummyLd BSL> o <- serializeElf elf'
+*DummyLd BSL> BSL.writeFile "helloWorld2" o
+*DummyLd BSL> 
 Leaving GHCi.
 
-[nix-shell:examples]$ chmod +x hellox
+[nix-shell:examples]$ chmod +x helloWorld2
 
-[nix-shell:examples]$ qemu-aarch64 hellox
+[nix-shell:examples]$ qemu-aarch64 helloWorld2
 Hello World!
 
 [nix-shell:examples]$ 
 ```
 
 Работает.
+
+## Заключение
+
+В статье даны примеры использования библиотеки `melf` и показано, как может быть определён встроенный в Хаскел DSL для генерации машинного кода.
diff --git a/examples/forwardLabelExe.dump.golden b/examples/forwardLabelExe.dump.golden
--- a/examples/forwardLabelExe.dump.golden
+++ b/examples/forwardLabelExe.dump.golden
@@ -20,8 +20,8 @@
             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
+                  d2 01 00 00 d4 00 00 00 00 6f 6b 0a 62 61 64 0a # .........ok.bad.
+                  total: 55
         }
-        segment table
 }
+segment table
diff --git a/examples/forwardLabelExe.layout.golden b/examples/forwardLabelExe.layout.golden
--- a/examples/forwardLabelExe.layout.golden
+++ b/examples/forwardLabelExe.layout.golden
@@ -2,7 +2,7 @@
 │┎ 0x00000000 H
 │┖ 0x0000003f
 │╓ 0x00000040 R
-│╙ 0x00000077
-│┎ 0x00000078 PT (1)
-│┖ 0x000000af
-└─ 0x000000af
+│╙ 0x00000076
+└─ 0x00000076
+ ┎ 0x00000078 PT (1)
+ ┖ 0x000000af
diff --git a/examples/helloWorldExe.dump.golden b/examples/helloWorldExe.dump.golden
--- a/examples/helloWorldExe.dump.golden
+++ b/examples/helloWorldExe.dump.golden
@@ -19,7 +19,7 @@
         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!....
+                  48 65 6c 6c 6f 20 57 6f 72 6c 64 21 0a          # Hello World!.
         }
-        segment table
 }
+segment table
diff --git a/examples/helloWorldExe.layout.golden b/examples/helloWorldExe.layout.golden
--- a/examples/helloWorldExe.layout.golden
+++ b/examples/helloWorldExe.layout.golden
@@ -2,7 +2,7 @@
 │┎ 0x00000000 H
 │┖ 0x0000003f
 │╓ 0x00000040 R
-│╙ 0x0000006f
-│┎ 0x00000070 PT (1)
-│┖ 0x000000a7
-└─ 0x000000a7
+│╙ 0x0000006c
+└─ 0x0000006c
+ ┎ 0x00000070 PT (1)
+ ┖ 0x000000a7
diff --git a/melf.cabal b/melf.cabal
--- a/melf.cabal
+++ b/melf.cabal
@@ -1,11 +1,11 @@
 cabal-version: 1.18
 
--- This file has been generated from package.yaml by hpack version 0.34.4.
+-- This file has been generated from package.yaml by hpack version 0.34.5.
 --
 -- see: https://github.com/sol/hpack
 
 name:           melf
-version:        1.0.1
+version:        1.0.2
 synopsis:       An Elf parser
 description:    Parser for ELF object format
 category:       Data
