base: add symbol support for dynamic libraries
authorBrandon Potter <brandon.potter@amd.com>
Thu, 17 Mar 2016 17:34:27 +0000 (10:34 -0700)
committerBrandon Potter <brandon.potter@amd.com>
Thu, 17 Mar 2016 17:34:27 +0000 (10:34 -0700)
Libraries are loaded into the process address space using the
mmap system call. Conveniently, this happens to be a good
time to update the process symbol table with the library's
incoming symbols so we handle the table update from within the
system call.

This works just like an application's normal symbols. The only
difference between a dynamic library and a main executable is
when the symbol table update occurs. The symbol table update for
an executable happens at program load time and is finished before
the process ever begins executing. Since dynamic linking happens
at runtime, the symbol loading happens after the library is
first loaded into the process address space. The library binary
is examined at this time for a symbol section and that section
is parsed for symbol types with specific bindings (global,
local, weak). Subsequently, these symbols are added to the table
and are available for use by gem5 for things like trace
generation.

Checkpointing should work just as it did previously. The address
space (and therefore the library) will be recorded and the symbol
table will be entirely recorded. (It's not possible to do anything
clever like checkpoint a program and then load the program back
with different libraries with LD_LIBRARY_PATH, because the
library becomes part of the address space after being loaded.)

17 files changed:
src/arch/arm/freebsd/system.cc
src/arch/arm/linux/system.cc
src/arch/sparc/system.cc
src/base/loader/aout_object.cc
src/base/loader/aout_object.hh
src/base/loader/dtb_object.cc
src/base/loader/dtb_object.hh
src/base/loader/ecoff_object.cc
src/base/loader/ecoff_object.hh
src/base/loader/elf_object.cc
src/base/loader/elf_object.hh
src/base/loader/object_file.hh
src/base/loader/raw_object.cc
src/base/loader/raw_object.hh
src/sim/process.cc
src/sim/process.hh
src/sim/syscall_emul.hh

index d6f3e4e9ab958441c60fa30b5d7eb8b4d07ad855..da427e83230a36c1b9a13e9f86232a17b2518561 100644 (file)
@@ -86,8 +86,8 @@ FreebsdArmSystem::initState()
     // to do this permanently, for but early bootup work
     // it is helpful.
     if (params()->early_kernel_symbols) {
-        kernel->loadGlobalSymbols(kernelSymtab, loadAddrMask);
-        kernel->loadGlobalSymbols(debugSymbolTable, loadAddrMask);
+        kernel->loadGlobalSymbols(kernelSymtab, 0, 0, loadAddrMask);
+        kernel->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask);
     }
 
     // Setup boot data structure
index c22ce160fc22ba1bbd046d99ce70f189aa964389..a78bab5bfa6505895dfb73ae0d353fb7d6b88a9c 100644 (file)
@@ -110,8 +110,8 @@ LinuxArmSystem::initState()
     // to do this permanently, for but early bootup work
     // it is helpful.
     if (params()->early_kernel_symbols) {
-        kernel->loadGlobalSymbols(kernelSymtab, loadAddrMask);
-        kernel->loadGlobalSymbols(debugSymbolTable, loadAddrMask);
+        kernel->loadGlobalSymbols(kernelSymtab, 0, 0, loadAddrMask);
+        kernel->loadGlobalSymbols(debugSymbolTable, 0, 0, loadAddrMask);
     }
 
     // Setup boot data structure
index b6fa645cec8cc9585e4cb14131f8f38ddcae4ece..5c7f06db3056a9e9a34fc29012fff9943f164e40 100644 (file)
@@ -115,7 +115,7 @@ SparcSystem::SparcSystem(Params *p)
 
     // Strip off the rom address so when the hypervisor is copied into memory we
     // have symbols still
-    if (!hypervisor->loadLocalSymbols(debugSymbolTable, 0xFFFFFF))
+    if (!hypervisor->loadLocalSymbols(debugSymbolTable, 0, 0, 0xFFFFFF))
         panic("could not load hypervisor symbols\n");
 
     if (!nvram->loadGlobalSymbols(debugSymbolTable))
index 07acc8fbd5c78d96bd253efb03e1a27c656d257f..468b1b1f09719b6afbd9f872acf5ae5d6a89f925 100644 (file)
@@ -80,14 +80,23 @@ AoutObject::AoutObject(const string &_filename,
 
 
 bool
-AoutObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
+AoutObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                           Addr addr_mask)
+{
+    return false;
+}
+
+bool
+AoutObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                              Addr addr_mask)
 {
     // a.out symbols not supported yet
     return false;
 }
 
 bool
-AoutObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
+AoutObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                             Addr addr_mask)
 {
     // a.out symbols not supported yet
     return false;
index 110dcfd366966a1b2dc3e289bc705e89e3093d6d..65ed7ca0fe2c2b7cef0d5af5d4534b306274988c 100644 (file)
@@ -48,10 +48,13 @@ class AoutObject : public ObjectFile
   public:
     virtual ~AoutObject() {}
 
-    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max());
-    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max());
+    virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
+                                Addr offset = 0, Addr addr_mask = maxAddr);
+    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
+                                   Addr offset = 0,
+                                   Addr addr_mask = maxAddr);
+    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
+                                  Addr offset = 0, Addr addr_mask = maxAddr);
 
     static ObjectFile *tryFile(const std::string &fname,
                                size_t len, uint8_t *data);
index ead667f1112d794157386575eb0b24ee476c8293..e9bbceec497d49f0794c037ad79b33620f880d8f 100644 (file)
@@ -171,16 +171,24 @@ DtbObject::findReleaseAddr()
     return rel_addr;
 }
 
+bool
+DtbObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                          Addr addr_mask)
+{
+    return false;
+}
 
 bool
-DtbObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
+DtbObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                             Addr addr_mask)
 {
     // nothing to do here
     return false;
 }
 
 bool
-DtbObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
+DtbObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                            Addr addr_mask)
 {
     // nothing to do here
     return false;
index 451b52a4c727b96052e20b0017d5ba355e44c705..c49b144ac804403f338cafcb945e42be4029c757 100644 (file)
@@ -66,10 +66,12 @@ class DtbObject : public ObjectFile
          */
         Addr findReleaseAddr();
 
-        bool loadGlobalSymbols(SymbolTable *symtab,
-            Addr addrMask = std::numeric_limits<Addr>::max());
-        bool loadLocalSymbols(SymbolTable *symtab,
-            Addr addrMask = std::numeric_limits<Addr>::max());
+        bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
+                            Addr offset = 0, Addr addrMask = maxAddr);
+        bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
+                               Addr offset = 0, Addr addrMask = maxAddr);
+        bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
+                              Addr offset = 0, Addr addrMask = maxAddr);
 
         /** Static function that tries to load file as a
           * flattened device tree blob.
index c3c1c1108cc3b6f1a91b9928a07f282582f3d26e..1869efa136732aff5085de9cb5e651c18b945244 100644 (file)
@@ -89,9 +89,18 @@ EcoffObject::EcoffObject(const string &_filename, size_t _len, uint8_t *_data,
              bss.baseAddr, bss.size);
 }
 
+bool
+EcoffObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                            Addr addr_mask)
+{
+    bool retval = loadGlobalSymbols(symtab, base, offset, addr_mask);
+    retval = retval && loadLocalSymbols(symtab, base, offset, addr_mask);
+    return retval;
+}
 
 bool
-EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
+EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                               Addr addr_mask)
 {
     if (!symtab)
         return false;
@@ -120,7 +129,8 @@ EcoffObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
 }
 
 bool
-EcoffObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
+EcoffObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                              Addr addr_mask)
 {
     if (!symtab)
         return false;
index 0a5a43f72dcd7be7fe7f031cd9add26d965b238e..b1ae91107e1ff4d94f6e5c3439bff86fa999ca81 100644 (file)
@@ -51,10 +51,12 @@ class EcoffObject : public ObjectFile
   public:
     virtual ~EcoffObject() {}
 
-    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max());
-    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max());
+    virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
+                                Addr offset = 0, Addr addr_mask = maxAddr);
+    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
+                                  Addr offset = 0, Addr addr_mask = maxAddr);
+    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
+                                  Addr offset = 0, Addr addr_mask = maxAddr);
 
     static ObjectFile *tryFile(const std::string &fname,
                                size_t len, uint8_t *data);
index fb5ec4c14d46d3192a47197b0590e8daf9f9eb5f..73c1c5dcd2372059f03cf7703b3fc136ebc6602d 100644 (file)
@@ -396,7 +396,8 @@ ElfObject::ElfObject(const std::string &_filename, size_t _len,
 
 
 bool
-ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask)
+ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask,
+                           Addr base, Addr offset)
 {
     if (!symtab)
         return false;
@@ -432,9 +433,11 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask)
                 if (GELF_ST_BIND(sym.st_info) == binding) {
                     char *sym_name = elf_strptr(elf, shdr.sh_link, sym.st_name);
                     if (sym_name && sym_name[0] != '$') {
-                        DPRINTF(Loader, "Symbol: %-40s value %#x\n",
-                                sym_name, sym.st_value);
-                        symtab->insert(sym.st_value & mask, sym_name);
+                        Addr value = sym.st_value - base + offset;
+                        if (symtab->insert(value & mask, sym_name)) {
+                            DPRINTF(Loader, "Symbol: %-40s value %#x\n",
+                                    sym_name, value);
+                        }
                     }
                 }
             }
@@ -449,23 +452,45 @@ ElfObject::loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask)
 }
 
 bool
-ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr addr_mask)
+ElfObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                          Addr addr_mask)
 {
-    return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask);
+    return (loadGlobalSymbols(symtab, base, offset, addr_mask) &&
+            loadLocalSymbols(symtab, base, offset, addr_mask) &&
+            loadWeakSymbols(symtab, base, offset, addr_mask));
 }
 
 bool
-ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr addr_mask)
+ElfObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                             Addr addr_mask)
 {
-    bool found_local = loadSomeSymbols(symtab, STB_LOCAL, addr_mask);
-    bool found_weak = loadSomeSymbols(symtab, STB_WEAK, addr_mask);
-    return found_local || found_weak;
+    if (interpreter) {
+        interpreter->loadSomeSymbols(symtab, STB_GLOBAL, addr_mask,
+                                     base, offset);
+    }
+    return loadSomeSymbols(symtab, STB_GLOBAL, addr_mask, base, offset);
 }
 
 bool
-ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr addr_mask)
+ElfObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                            Addr addr_mask)
 {
-    return loadSomeSymbols(symtab, STB_WEAK, addr_mask);
+    if (interpreter) {
+        interpreter->loadSomeSymbols(symtab, STB_LOCAL, addr_mask,
+                                     base, offset);
+    }
+    return loadSomeSymbols(symtab, STB_LOCAL, addr_mask, base, offset);
+}
+
+bool
+ElfObject::loadWeakSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                           Addr addr_mask)
+{
+    if (interpreter) {
+        interpreter->loadSomeSymbols(symtab, STB_WEAK, addr_mask,
+                                     base, offset);
+    }
+    return loadSomeSymbols(symtab, STB_WEAK, addr_mask, base, offset);
 }
 
 bool
index cec20a47a784062b420a9d6eeb312ecc31e7f673..aa28cd62a72bdeabfb81d30bac268f1bafeced57 100644 (file)
@@ -81,7 +81,8 @@ class ElfObject : public ObjectFile
     Addr ldMax;
 
     /// Helper functions for loadGlobalSymbols() and loadLocalSymbols().
-    bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask);
+    bool loadSomeSymbols(SymbolTable *symtab, int binding, Addr mask,
+                         Addr base, Addr offset);
 
     ElfObject(const std::string &_filename, size_t _len, uint8_t *_data,
               Arch _arch, OpSys _opSys);
@@ -94,15 +95,25 @@ class ElfObject : public ObjectFile
   public:
     virtual ~ElfObject() {}
 
-    bool loadSections(PortProxy& memProxy,
-            Addr addrMask = std::numeric_limits<Addr>::max(),
-            Addr offset = 0) override;
-    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max()) override;
-    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max()) override;
-    virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max()) override;
+    bool loadSections(PortProxy& mem_proxy, Addr addr_mask = maxAddr,
+                      Addr offset = 0) override;
+
+    virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
+                                Addr offset = 0, Addr addr_mask = maxAddr)
+                                override;
+
+    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
+                                   Addr offset = 0, Addr addr_mask = maxAddr)
+                                   override;
+
+    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
+                                  Addr offset = 0, Addr addr_mask = maxAddr)
+                                  override;
+
+    virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base = 0,
+                                 Addr offset = 0, Addr addr_mask = maxAddr)
+                                 override;
+
 
     virtual ObjectFile *getInterpreter() const override
     { return interpreter; }
index fb30118e09bc476cdfce81cc783c5d3d352855d0..b2628a0d0118f1b7f4f58195d315673a9c9f102e 100644 (file)
@@ -82,15 +82,19 @@ class ObjectFile
   public:
     virtual ~ObjectFile();
 
-    virtual bool loadSections(PortProxy& memProxy, Addr addrMask =
-                              std::numeric_limits<Addr>::max(),
-                              Addr offset = 0);
-    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max()) = 0;
-    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max()) = 0;
-    virtual bool loadWeakSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max())
+    static const Addr maxAddr = std::numeric_limits<Addr>::max();
+
+    virtual bool loadSections(PortProxy& mem_proxy,
+                              Addr mask = maxAddr, Addr offset = 0);
+
+    virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
+                                Addr offset = 0, Addr mask = maxAddr) = 0;
+    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
+                                   Addr offset = 0, Addr mask = maxAddr) = 0;
+    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
+                                  Addr offset = 0, Addr mask = maxAddr) = 0;
+    virtual bool loadWeakSymbols(SymbolTable *symtab, Addr base = 0,
+                                 Addr offset = 0, Addr mask = maxAddr)
     { return false; }
 
     virtual ObjectFile *getInterpreter() const { return nullptr; }
@@ -121,7 +125,7 @@ class ObjectFile
     Section data;
     Section bss;
 
-    bool loadSection(Section *sec, PortProxy& memProxy, Addr addrMask,
+    bool loadSection(Section *sec, PortProxy& mem_proxy, Addr mask,
                      Addr offset = 0);
     void setGlobalPointer(Addr global_ptr) { globalPtr = global_ptr; }
 
index 73d8372ef2c376d1d5958b096239824b400f7f59..35a952741ee30e6dd577b94bf1741ac60a73a93d 100644 (file)
@@ -62,21 +62,30 @@ RawObject::RawObject(const std::string &_filename, size_t _len,
 }
 
 bool
-RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr addrMask)
+RawObject::loadAllSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                          Addr addr_mask)
+{
+    return true;
+}
+
+bool
+RawObject::loadGlobalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                             Addr addr_mask)
 {
 /*    int fnameStart = filename.rfind('/',filename.size()) + 1;
     int extStart = filename.rfind('.',filename.size());
-    symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart,
+    symtab->insert(text.baseAddr & addr_mask, filename.substr(fnameStart,
                 extStart-fnameStart) + "_start");*/
     return true;
 }
 
 bool
-RawObject::loadLocalSymbols(SymbolTable *symtab, Addr addrMask)
+RawObject::loadLocalSymbols(SymbolTable *symtab, Addr base, Addr offset,
+                            Addr addr_mask)
 {
 /*    int fnameStart = filename.rfind('/',filename.size()) + 1;
     int extStart = filename.rfind('.',filename.size());
-    symtab->insert(text.baseAddr & addrMask, filename.substr(fnameStart,
+    symtab->insert(text.baseAddr & addr_mask, filename.substr(fnameStart,
                 extStart-fnameStart) + "_start");*/
     return true;
 }
index 3865425d074f746d1a9f2a82006a32acecd930aa..6931a1321948bde7778795120d2a978f1b90f8b0 100644 (file)
@@ -41,10 +41,13 @@ class RawObject: public ObjectFile
   public:
     virtual ~RawObject() {}
 
-    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max());
-    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr addrMask =
-            std::numeric_limits<Addr>::max());
+    virtual bool loadAllSymbols(SymbolTable *symtab, Addr base = 0,
+                                Addr offset = 0, Addr addr_mask = maxAddr);
+    virtual bool loadGlobalSymbols(SymbolTable *symtab, Addr base = 0,
+                                   Addr offset = 0,
+                                   Addr addr_mask = maxAddr);
+    virtual bool loadLocalSymbols(SymbolTable *symtab, Addr base = 0,
+                                  Addr offset = 0, Addr addr_mask = maxAddr);
 
     static ObjectFile *tryFile(const std::string &fname, size_t len,
             uint8_t *data);
index 7fa160995c726ba19fae050252fa4ca24c9c305f..d0dd3d92b71ca4f13f918bb75f5905acfd093d23 100644 (file)
@@ -543,10 +543,17 @@ LiveProcess::updateBias()
 }
 
 
+ObjectFile *
+LiveProcess::getInterpreter()
+{
+    return objFile->getInterpreter();
+}
+
+
 Addr
 LiveProcess::getBias()
 {
-    ObjectFile *interp = objFile->getInterpreter();
+    ObjectFile *interp = getInterpreter();
 
     return interp ? interp->bias() : objFile->bias();
 }
@@ -555,7 +562,7 @@ LiveProcess::getBias()
 Addr
 LiveProcess::getStartPC()
 {
-    ObjectFile *interp = objFile->getInterpreter();
+    ObjectFile *interp = getInterpreter();
 
     return interp ? interp->entryPoint() : objFile->entryPoint();
 }
index aa4c7a0085c0bf2fea089515ee67ab0586de8ab3..54e6b2df257704dda45d381110efc4a8397e228c 100644 (file)
@@ -341,6 +341,8 @@ class LiveProcess : public Process
     // bias are not available when the object file is created.
     void updateBias();
 
+    ObjectFile *getInterpreter();
+
     Addr getBias();
     Addr getStartPC();
 
index 71c0dd09024180fd526b959ed37c10ae4dac6b2b..e9ed130f08f46bd45fa30a9d431604189c731a85 100644 (file)
 
 #ifdef __CYGWIN32__
 #include <sys/fcntl.h>  // for O_BINARY
+
 #endif
+#include <fcntl.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/time.h>
 #include <sys/uio.h>
-#include <fcntl.h>
 
 #include <cerrno>
 #include <string>
 
 #include "base/chunk_generator.hh"
 #include "base/intmath.hh"      // for RoundUp
+#include "base/loader/object_file.hh"
 #include "base/misc.hh"
 #include "base/trace.hh"
 #include "base/types.hh"
@@ -1354,6 +1356,31 @@ mmapImpl(SyscallDesc *desc, int num, LiveProcess *p, ThreadContext *tc,
         // Cleanup the mmap region before exiting this function.
         munmap(pmap, length);
 
+        // Maintain the symbol table for dynamic executables.
+        // The loader will call mmap to map the images into its address
+        // space and we intercept that here. We can verify that we are
+        // executing inside the loader by checking the program counter value.
+        // XXX: with multiprogrammed workloads or multi-node configurations,
+        // this will not work since there is a single global symbol table.
+        ObjectFile *interpreter = p->getInterpreter();
+        if (interpreter) {
+            Addr text_start = interpreter->textBase();
+            Addr text_end = text_start + interpreter->textSize();
+
+            Addr pc = tc->pcState().pc();
+
+            if (pc >= text_start && pc < text_end) {
+                FDEntry *fde = p->getFDEntry(tgt_fd);
+
+                ObjectFile *lib = createObjectFile(fde->filename);
+
+                if (lib) {
+                    lib->loadAllSymbols(debugSymbolTable,
+                                        lib->textBase(), start);
+                }
+            }
+        }
+
         // Note that we do not zero out the remainder of the mapping. This
         // is done by a real system, but it probably will not affect
         // execution (hopefully).