private void AskLinkerToCreateMethodTable(string methodTableName, IList <RuntimeMethod> methodTable, IList <string> headerlinks)
        {
            int methodTableSize = ((headerlinks == null ? 0 : headerlinks.Count) + (methodTable == null ? 0 : methodTable.Count)) * typeLayout.NativePointerSize;

            Debug.WriteLine("Method Table: " + methodTableName);

            using (Stream stream = linker.Allocate(methodTableName, SectionKind.Text, methodTableSize, typeLayout.NativePointerAlignment))
            {
                stream.Position = methodTableSize;
            }

            int offset = 0;

            if (headerlinks != null)
            {
                foreach (string link in headerlinks)
                {
                    if (!string.IsNullOrEmpty(link))
                    {
                        Debug.WriteLine("  # " + (offset / typeLayout.NativePointerSize).ToString() + " " + link);
                        linker.Link(LinkType.AbsoluteAddress | LinkType.I4, methodTableName, offset, 0, link, IntPtr.Zero);
                    }
                    else
                    {
                        Debug.WriteLine("  # " + (offset / typeLayout.NativePointerSize).ToString() + " [null]");
                    }
                    offset += typeLayout.NativePointerSize;
                }
            }

            if (methodTable != null)
            {
                foreach (RuntimeMethod method in methodTable)
                {
                    if (!method.IsAbstract)
                    {
                        Debug.WriteLine("  # " + (offset / typeLayout.NativePointerSize).ToString() + " " + method.ToString());
                        linker.Link(LinkType.AbsoluteAddress | LinkType.I4, methodTableName, offset, 0, method.ToString(), IntPtr.Zero);
                    }
                    else
                    {
                        Debug.WriteLine("  # " + (offset / typeLayout.NativePointerSize).ToString() + " [null]");
                    }
                    offset += typeLayout.NativePointerSize;
                }
            }
        }
        /// <summary>
        /// Writes the multiboot _header.
        /// </summary>
        /// <param name="compiler">The assembly compiler.</param>
        /// <param name="linker">The linker.</param>
        /// <param name="entryPoint">The virtualAddress of the multiboot compliant entry point.</param>
        private void WriteMultibootHeader(AssemblyCompiler compiler, IAssemblyLinker linker, IntPtr entryPoint)
        {
            // HACK: According to the multiboot specification this _header must be within the first 8K of the
            // kernel binary. Since the text section is always first, this should take care of the problem.
            using (Stream stream = linker.Allocate(MultibootHeaderSymbolName, SectionKind.Text, 64, 4))
                using (BinaryWriter bw = new BinaryWriter(stream, Encoding.ASCII)) {
                    // flags - multiboot flags
                    uint flags = /*HEADER_MB_FLAG_VIDEO_MODES_REQUIRED | */ HEADER_MB_FLAG_MEMORY_INFO_REQUIRED | HEADER_MB_FLAG_MODULES_PAGE_ALIGNED;
                    // The multiboot _header checksum
                    uint csum = 0;
                    // header_addr is the load virtualAddress of the multiboot _header
                    uint header_addr = 0;
                    // load_addr is the base virtualAddress of the binary in memory
                    uint load_addr = 0;
                    // load_end_addr holds the virtualAddress past the last byte to load From the image
                    uint load_end_addr = 0;
                    // bss_end_addr is the virtualAddress of the last byte to be zeroed out
                    uint bss_end_addr = 0;
                    // entry_point the load virtualAddress of the entry point to invoke
                    uint entry_point = (uint)entryPoint.ToInt32();

                    // Are we linking an ELF binary?
                    if (!(linker is Elf32Linker || linker is Elf64Linker))
                    {
                        // Check the linker layout settings
                        if (linker.LoadSectionAlignment != linker.VirtualSectionAlignment)
                        {
                            throw new LinkerException(@"Load and virtual section alignment must be identical if you are booting non-ELF binaries with a multiboot bootloader.");
                        }

                        // No, special multiboot treatment required
                        flags |= HEADER_MB_FLAG_NON_ELF_BINARY;

                        header_addr   = (uint)(linker.GetSection(SectionKind.Text).VirtualAddress.ToInt64() + linker.GetSymbol(MultibootHeaderSymbolName).SectionAddress);
                        load_addr     = (uint)linker.BaseAddress;
                        load_end_addr = 0;
                        bss_end_addr  = 0;
                    }

                    // Calculate the checksum
                    csum = unchecked (0U - HEADER_MB_MAGIC - flags);

                    bw.Write(HEADER_MB_MAGIC);
                    bw.Write(flags);
                    bw.Write(csum);
                    bw.Write(header_addr);
                    bw.Write(load_addr);
                    bw.Write(load_end_addr);
                    bw.Write(bss_end_addr);

                    // HACK: Symbol has been hacked. What's the correct way to do this?
                    linker.Link(LinkType.AbsoluteAddress | LinkType.I4, MultibootHeaderSymbolName, (int)stream.Position, 0, @"Mosa.Tools.Compiler.LinkerGenerated.<$>MultibootInit()", IntPtr.Zero);

                    bw.Write(videoMode);
                    bw.Write(videoWidth);
                    bw.Write(videoHeight);
                    bw.Write(videoDepth);
                }
        }
        /// <summary>
        /// Calls the specified target.
        /// </summary>
        /// <param name="symbolOperand">The symbol operand.</param>
        public void Call(SymbolOperand symbolOperand)
        {
            long address = _linker.Link(
                LinkType.RelativeOffset | LinkType.I4,
                _compiler.Method.ToString(),
                (int)(_codeStream.Position - _codeStreamBasePosition),
                (int)(_codeStream.Position - _codeStreamBasePosition) + 4,
                symbolOperand.Name,
                IntPtr.Zero
                );

            if (address == 0L)
            {
                this.WriteByte(0);
                this.WriteByte(0);
                this.WriteByte(0);
                this.WriteByte(0);
            }
            else
            {
                this._codeStream.Position += 4;
            }
        }
        /// <summary>
        /// Writes the multiboot _header.
        /// </summary>
        /// <param name="compiler">The assembly compiler.</param>
        /// <param name="linker">The linker.</param>
        /// <param name="entryPoint">The virtualAddress of the multiboot compliant entry point.</param>
        private void WriteMultibootHeader(AssemblyCompiler compiler, IAssemblyLinker linker, IntPtr entryPoint)
        {
            // HACK: According to the multiboot specification this _header must be within the first 8K of the
            // kernel binary. Since the text section is always first, this should take care of the problem.
            using (Stream stream = linker.Allocate(MultibootHeaderSymbolName, SectionKind.Text, 64, 4))
            using (BinaryWriter bw = new BinaryWriter(stream, Encoding.ASCII)) {
                // flags - multiboot flags
                uint flags = /*HEADER_MB_FLAG_VIDEO_MODES_REQUIRED | */HEADER_MB_FLAG_MEMORY_INFO_REQUIRED | HEADER_MB_FLAG_MODULES_PAGE_ALIGNED;
                // The multiboot _header checksum
                uint csum = 0;
                // header_addr is the load virtualAddress of the multiboot _header
                uint header_addr = 0;
                // load_addr is the base virtualAddress of the binary in memory
                uint load_addr = 0;
                // load_end_addr holds the virtualAddress past the last byte to load From the image
                uint load_end_addr = 0;
                // bss_end_addr is the virtualAddress of the last byte to be zeroed out
                uint bss_end_addr = 0;
                // entry_point the load virtualAddress of the entry point to invoke
                uint entry_point = (uint)entryPoint.ToInt32();

                // Are we linking an ELF binary?
                if (!(linker is Elf32Linker || linker is Elf64Linker)) {
                    // Check the linker layout settings
                    if (linker.LoadSectionAlignment != linker.VirtualSectionAlignment)
                        throw new LinkerException(@"Load and virtual section alignment must be identical if you are booting non-ELF binaries with a multiboot bootloader.");

                    // No, special multiboot treatment required
                    flags |= HEADER_MB_FLAG_NON_ELF_BINARY;

                    header_addr = (uint)(linker.GetSection(SectionKind.Text).VirtualAddress.ToInt64() + linker.GetSymbol(MultibootHeaderSymbolName).SectionAddress);
                    load_addr = (uint)linker.BaseAddress;
                    load_end_addr = 0;
                    bss_end_addr = 0;
                }

                // Calculate the checksum
                csum = unchecked(0U - HEADER_MB_MAGIC - flags);

                bw.Write(HEADER_MB_MAGIC);
                bw.Write(flags);
                bw.Write(csum);
                bw.Write(header_addr);
                bw.Write(load_addr);
                bw.Write(load_end_addr);
                bw.Write(bss_end_addr);

                // HACK: Symbol has been hacked. What's the correct way to do this?
                linker.Link(LinkType.AbsoluteAddress | LinkType.I4, MultibootHeaderSymbolName, (int)stream.Position, 0, @"Mosa.Tools.Compiler.LinkerGenerated.<$>MultibootInit()", IntPtr.Zero);

                bw.Write(videoMode);
                bw.Write(videoWidth);
                bw.Write(videoHeight);
                bw.Write(videoDepth);
            }
        }
Example #5
0
 /// <summary>
 /// Calls the specified target.
 /// </summary>
 /// <param name="target">The target.</param>
 public void Call(RuntimeMethod target)
 {
     _linker.Link(LinkType.RelativeOffset | LinkType.I4, _compiler.Method, (int)(_codeStream.Position - _codeStreamBasePosition) - 4, (int)(_codeStream.Position - _codeStreamBasePosition), target, IntPtr.Zero);
 }