diff --git a/CMakeLists.txt b/CMakeLists.txt index 215a0ab..9e2bd7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS 1) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_CXX_STANDARD 17) -find_package(Boost COMPONENTS program_options REQUIRED) +find_package(Boost COMPONENTS process program_options REQUIRED) find_package(FLEX) include_directories(${Boost_INCLUDE_DIR}) diff --git a/backend/target.cpp b/backend/target.cpp index aa105c1..3b5918e 100644 --- a/backend/target.cpp +++ b/backend/target.cpp @@ -1,90 +1,14 @@ #include "elna/backend/target.hpp" #include "elna/backend/riscv.hpp" #include +#include +#include namespace elna::riscv { - elfio_section_writer::iterator::reference elfio_section_writer::iterator::operator*() const noexcept - { - return payload; - } - - elfio_section_writer::iterator::pointer elfio_section_writer::iterator::operator->() const noexcept - { - return &payload; - } - - elfio_section_writer::iterator& elfio_section_writer::iterator::operator++() - { - this->payload.data += *this->sizes; - this->payload.label = *(++this->labels); - this->payload.size = *(++this->sizes); - - return *this; - } - - elfio_section_writer::iterator& elfio_section_writer::iterator::operator++(int) - { - auto tmp = *this; - ++(*this); - return *this; - } - - bool elfio_section_writer::iterator::operator==(const iterator& that) const - { - return this->labels == that.labels; - } - - bool elfio_section_writer::iterator::operator!=(const iterator& that) const - { - return !(*this == that); - } - - elfio_section_writer::elfio_section_writer(ELFIO::section *section) - : m_section(section) - { - } - - void elfio_section_writer::operator()(const std::string& label, const std::byte *data, std::size_t size) - { - labels.push_back(label); - sizes.push_back(size); - m_section->append_data(reinterpret_cast(data), size); - } - - std::pair elfio_section_writer::operator()(const std::byte *data, std::size_t size) - { - auto found = std::find_if(begin(), end(), - [data, size](elfio_section_writer::entry entry) { - return size == entry.size && std::memcmp(entry.data, data, size) == 0; - }); - if (found == end()) - { - (*this)(".CL" + std::to_string(labels.size()), data, size); - return std::pair(labels.back(), true); - } - return std::pair(found->label, false); - } - - elfio_section_writer::iterator elfio_section_writer::begin() const - { - return elfio_section_writer::iterator(labels.cbegin(), sizes.cbegin(), - reinterpret_cast(m_section->get_data())); - } - - elfio_section_writer::iterator elfio_section_writer::end() const - { - return elfio_section_writer::iterator(labels.cend(), sizes.cend()); - } - - ELFIO::section *elfio_section_writer::section() noexcept - { - return m_section; - } - - elfio_writer::elfio_writer(ELFIO::section *text, ELFIO::section *read_only, + elfio_writer::elfio_writer(ELFIO::section *text, ELFIO::symbol_section_accessor symbol_accessor, ELFIO::string_section_accessor string_accessor) - : text(text), read_only(elfio_section_writer(read_only)), + : text(text), symbol_accessor(symbol_accessor), string_accessor(string_accessor) { } @@ -100,20 +24,6 @@ namespace elna::riscv return text->get_size(); } - std::string_view elfio_writer::sink(const std::byte *data, std::size_t size) - { - auto offset = read_only.section()->get_size(); - auto [result, inserted] = read_only(data, size); - - if (inserted) - { - this->symbol_accessor.add_symbol(this->string_accessor, result.data(), offset, - result.size(), ELFIO::STB_LOCAL, ELFIO::STT_NOTYPE, 0, - read_only.section()->get_index()); - } - return result; - } - void elfio_writer::sink(const std::string& label) { this->symbol_accessor.add_symbol(this->string_accessor, "printf", 0x00000000, 0, @@ -125,6 +35,35 @@ namespace elna::riscv return this->text->get_size(); } + process_writer::process_writer(boost::asio::io_context& context) + : pipe(context) + { + } + + std::size_t process_writer::sink(const std::string& label, const std::byte *data, std::size_t size) + { + auto network_order_size = boost::endian::native_to_big(static_cast(size)); + + auto written = boost::asio::write(this->pipe, boost::asio::buffer(label.data(), label.size() + 1)); + boost::asio::write(this->pipe, boost::asio::buffer(&network_order_size, 2)); + boost::asio::write(this->pipe, boost::asio::buffer(data, size)); + this->text_size += written; + + return written; + } + + void process_writer::sink(const std::string& label) + { + std::uint16_t data_size{ 0 }; + boost::asio::write(this->pipe, boost::asio::buffer(label.data(), label.size() + 1)); + boost::asio::write(this->pipe, boost::asio::buffer(&data_size, 2)); + } + + std::size_t process_writer::size() const + { + return this->text_size; + } + std::ptrdiff_t lookup(ELFIO::symbol_section_accessor symbol_accessor, const std::string& label) { for (ptrdiff_t j = 0; j < symbol_accessor.get_symbols_num(); ++j) @@ -188,18 +127,21 @@ namespace elna::riscv rel_sec->set_link(sym_sec->get_index()); rel_sec->set_flags(ELFIO::SHF_ALLOC); - // Create read only data section - ELFIO::section* ro_sec = writer.sections.add(".rodata"); - ro_sec->set_type(ELFIO::SHT_PROGBITS); - ro_sec->set_flags(ELFIO::SHF_ALLOC); - ro_sec->set_addr_align(0x4); - // Create symbol relocation table writers ELFIO::symbol_section_accessor syma(writer, sym_sec); ELFIO::relocation_section_accessor rela(writer, rel_sec); - auto _writer = std::make_shared(text_sec, ro_sec, syma, stra); - auto references = generate(intermediate_code_generator, table, _writer); + auto writer1 = std::make_shared(text_sec, syma, stra); + boost::asio::io_context ctx; + auto writer2 = std::make_shared(ctx); + boost::process::process child(ctx, "./build/hs/elna", {}, + boost::process::process_stdio{ { writer2->pipe }, nullptr, nullptr }); + + auto references = generate(intermediate_code_generator, table, writer1); + generate(intermediate_code_generator, table, writer2); + + writer2->pipe.close(); + child.wait(); syma.arrange_local_symbols(); diff --git a/elna.cabal b/elna.cabal index 96f26c4..c4dcdc2 100644 --- a/elna.cabal +++ b/elna.cabal @@ -17,6 +17,7 @@ extra-source-files: TODO README common warnings build-depends: base ^>=4.19.1.0, + bytestring ^>= 0.12.1, megaparsec ^>= 9.6, text ^>= 2.0 ghc-options: -Wall @@ -33,7 +34,6 @@ library elna-internal exposed-modules: Language.Elna.Object.Elf build-depends: - bytestring ^>= 0.12.1, hashable ^>= 1.4.3, parser-combinators ^>= 1.3, transformers ^>= 0.6.1, @@ -45,5 +45,5 @@ executable elna import: warnings main-is: Main.hs build-depends: - elna:elna-internal + elna:elna-internal hs-source-dirs: src diff --git a/include/elna/backend/target.hpp b/include/elna/backend/target.hpp index 2b3a1af..f738dbc 100644 --- a/include/elna/backend/target.hpp +++ b/include/elna/backend/target.hpp @@ -2,92 +2,37 @@ #include "elna/source/parser.hpp" #include "elna/source/optimizer.hpp" +#include #include #include namespace elna::riscv { - /** - * Writer to a single label. - */ - struct elfio_section_writer - { - struct entry - { - std::string_view label; - const std::byte *data{ nullptr }; - std::size_t size{ 0 }; - }; - - /** - * An iterator over label and string pairs. - */ - struct iterator - { - using iterator_category = std::forward_iterator_tag; - using difference_type = ptrdiff_t; - using value_type = entry; - using pointer = const value_type *; - using reference = const value_type&; - - reference operator*() const noexcept; - pointer operator->() const noexcept; - iterator& operator++(); - iterator& operator++(int); - bool operator==(const iterator& that) const; - bool operator!=(const iterator& that) const; - - private: - std::vector::const_iterator labels; - std::vector::const_iterator sizes; - value_type payload; - - iterator(std::vector::const_iterator labels, std::vector::const_iterator sizes, - const std::byte *data) - : labels(labels), sizes(sizes) - { - if (data != nullptr) - { - payload = { *this->labels, data, *this->sizes}; - } - } - - iterator(std::vector::const_iterator labels, std::vector::const_iterator sizes) - : labels(labels), sizes(sizes), payload{} - { - } - - friend elfio_section_writer; - }; - explicit elfio_section_writer(ELFIO::section *section); - - void operator()(const std::string& label, const std::byte *data, std::size_t size); - std::pair operator()(const std::byte *data, std::size_t size); - - iterator begin() const; - iterator end() const; - - ELFIO::section *section() noexcept; - - private: - std::vector labels; - std::vector sizes; - ELFIO::section *m_section; - }; - class elfio_writer final : public source::writer { ELFIO::section *text; - elfio_section_writer read_only; ELFIO::symbol_section_accessor symbol_accessor; ELFIO::string_section_accessor string_accessor; public: - elfio_writer(ELFIO::section *text, ELFIO::section *read_only, ELFIO::symbol_section_accessor symbol_accessor, + elfio_writer(ELFIO::section *text, ELFIO::symbol_section_accessor symbol_accessor, ELFIO::string_section_accessor string_accessor); std::size_t sink(const std::string& label, const std::byte *data, std::size_t size) override; - std::string_view sink(const std::byte *data, std::size_t size) override; + void sink(const std::string& label) override; + std::size_t size() const override; + }; + + class process_writer final : public source::writer + { + std::size_t text_size{ 0 }; + + public: + boost::asio::writable_pipe pipe; + + process_writer(boost::asio::io_context& context); + + std::size_t sink(const std::string& label, const std::byte *data, std::size_t size) override; void sink(const std::string& label) override; std::size_t size() const override; }; diff --git a/include/elna/source/result.hpp b/include/elna/source/result.hpp index b75a38e..bd39e14 100644 --- a/include/elna/source/result.hpp +++ b/include/elna/source/result.hpp @@ -171,16 +171,6 @@ namespace elna::source */ virtual std::size_t sink(const std::string& label, const T *data, std::size_t size) = 0; - /** - * Writes data and returns a label under that the data can be accessed. - * - * \param data Data to be written. - * \param size Data size. - * - * \return Label for the symbol. - */ - virtual std::string_view sink(const T *data, std::size_t size) = 0; - /** * Creates an external symbol. */ diff --git a/src/Main.hs b/src/Main.hs index 04b7992..f5d8c90 100644 --- a/src/Main.hs +++ b/src/Main.hs @@ -2,5 +2,47 @@ module Main ( main ) where +import Language.Elna.Object.Elf () +import Data.ByteString (ByteString) +import qualified Data.ByteString as ByteString +import Data.Bits (Bits(..)) + +data Chunk + = ExternSymbolChunk ByteString + | SymbolDefinitionChunk ByteString ByteString + deriving Eq + +instance Show Chunk + where + show (ExternSymbolChunk label) + = "ExternExternSymbolChunk " + <> show label + show (SymbolDefinitionChunk label chunk) + = "SymbolDefinitionChunk " + <> show label + <> "(Size: " + <> show (ByteString.length chunk) + <> ")" + +splitContents :: [Chunk] -> ByteString -> [Chunk] +splitContents accumulator remaining + | ByteString.null remaining = accumulator + | otherwise = + let (label, withoutLabel) = ByteString.drop 1 + <$> ByteString.break (== 0) remaining + (rawSize, chunkAndRest) = ByteString.splitAt 2 withoutLabel + in case ByteString.unpack rawSize of + [0, 0] -> splitContents (ExternSymbolChunk label : accumulator) chunkAndRest + [x, y] -> + let chunkSize = shiftL (fromIntegral x) 8 .|. fromIntegral y + (chunk, remaining') = ByteString.splitAt chunkSize chunkAndRest + in splitContents (SymbolDefinitionChunk label chunk : accumulator) remaining' + _ -> ExternSymbolChunk label : accumulator + main :: IO () -main = putStrLn "Hello, Haskell!" +main = do + contents <- ByteString.getContents + writeFile "here.txt" + $ "Total length: " <> show (ByteString.length contents) <> "\n" + <> show (splitContents [] contents) <> "\n" + putStrLn "Hello, Haskell!"