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); } }
/// <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); }