Interfacing with ELF filesOverview of source translationExecutable versus LinkableRole of the LinkerELF HeaderSection-HeadersProgram-HeadersMemory: Physical vs. VirtualLinux ‘Executable’ ELF filesLinux ‘Linkable’ ELF filesOur ‘loadmap.cpp’ utility32-bit versus 16-bit codeExample: ‘as86’ ListingDemo-programMemory-MapSegment DescriptorsDescriptors (continued)Task-State SegmentTransition to Ring 3System-Call DispatcherSystem-Call ID-numbersDefining our jump-tableSetting up Interrupt-Gate 0x80Using our jump-tableOur ‘exit’ serviceOur ‘write’ serviceIn-Class ExerciseInterfacing with ELF filesAn introduction to the Executable and Linkable Format (ELF) binary file specification standardLibrary Files Object FilesAssembly Source FilesC/C++ Source and HeaderFilesOverview of source translationMakefileC/C++ Source and HeaderFilesAssembly Source FilesLinker Command FileUser-created filespreprocessorcompiler assemblerMake Utility Object Files Shared Object File Linkable Image File Executable Image File Link Map FileLinker and Locator Library FilesArchive UtilitySection-Header Table(optional)Executable versus LinkableELF HeaderSection 2 DataSection 3 Data…Section n DataSegment 1 DataSegment 2 DataSegment 3 Data…Segment n DataLinkable File Executable FileSection-Header TableProgram-Header Table(optional)Program-Header TableELF HeaderSection 1 DataRole of the LinkerELF HeaderSection-Header TableSection 1 DataSection 2 Data…Section n DataELF HeaderSection-Header TableSection 1 DataSection 2 Data…Section n DataELF HeaderProgram-Header TableSegment 1 DataSegment 2 Data…Segment n DataLinkable FileLinkable FileExecutable FileELF Header e_type e_machine e_version e_entry e_phoff e_shoff e_flags e_ehsize e_phentsize e_phnum e_shentsize e_shnum e_shstrndx e_ident [ EI_NIDENT ] Section-Header Table: e_shoff, e_shentsize, e_shnum, e_shstrndx Program-Header Table: e_phoff, e_phentsize, e_phnum, e_entrySection-Headers sh_name sh_type sh_flags sh_addr sh_offset sh_size sh_link sh_info sh_addralign sh_entsizeProgram-Headers p_type p_offset p_vaddr p_paddr p_filesz p_memsz p_flags p_alignMemory: Physical vs. VirtualVirtualAddressSpace(4 GB)Physicaladdress space(1 GB)Portions of physical memory are “mapped” by the CPU into regions of each task’s ‘virtual’ address-spaceLinux ‘Executable’ ELF files•The Executable ELF files produced by the Linux linker are configured for execution in a private ‘virtual’ address space, whereby every program gets loaded at the identical virtual memory-address (i.e., 0x08048000)•We will soon study the Pentium’s paging mechanism which makes this possible (i.e., after we have finished Project #2)Linux ‘Linkable’ ELF files•But it is possible that some ‘linkable’ ELF files are self-contained (i.e., they do not need to be linked with other object-files or libraries)•Our ‘manydots.o’ is such an example•So we can write our own system-code that can execute the instructions contained in a stand-alone ‘linkable’ object-module, using the CPU’s ‘segmented’ physical memoryOur ‘loadmap.cpp’ utility•We created a tool that ‘parses’ a linkable ELF file, to identify each section’s length, type, and location within the object-module•For those sections containing the ‘text’ and ‘data’ for the program, we build segment-descriptors, based on where the linkable image-file will reside in physical memory32-bit versus 16-bit code•The Linux compilers, and ‘as’ assembler, produce object-files that are intended to reside in ’32-bit’ memory-segments (i.e., the ‘default’ bit in the segment-descriptor is set to 1)•This affects the CPU’s interpretation of the machine-instructions that it fetches•Our ‘as86’ assembler can produce either 16-bit or 32-bit code (though its default is 16-bit code)•We can employ ‘USE32’ or ‘USE16’ directivesExample: ‘as86’ ListingUSE320x0000 01 D8 add eax, ebx0x0002 66 01 D8 add ax, bx0x0005 90 nopUSE160x0006 66 01 D8 add eax, ebx0x0009 01 D8 add ax, bx0x000B 90 nopENDDemo-program•We created a Linux program (‘hello.s’) that invokes two system-calls (‘write’ and ‘exit’)•We assembled it with the ‘as’ assembler:$ as hello.o –o hello.o•The linkable ELF object-file ‘hello.o’ is then written to our boot-disk (track 0, sector 14) using: $ dd if=hello.o of=/dev/fd0 seek=13•(It will get loaded into memory by ‘trackldr’)Memory-MapIVTROM-BIOS DATABOOT-LOADER‘try32bit.b’image Loadedfrom Track 0 of boot-diskby ‘trackldr.b’0x000100000x000118000x000004000x00007C00 ‘trackldr.b’ read from Track 0 of boot-disk by ROM-BIOS bootstrap‘hello.o’ imageSegment Descriptors•We created 32-bit segment-descriptors for the ‘text’ and ‘data’ sections of ‘hello.o’ (in a Local Descriptor Table) with DPL=3)•For the ‘.text’ section: offset in ELF file = 0x34 size = 0x23•So its segment-descriptor is:.WORD 0x0023, 0x1834, 0xFA01, 0x0040 (base-address = load-address + file-offset)Descriptors (continued)•For the ‘.data’ section:offset in ELF file = 0x58 size = 0x0D•So its segment-descriptor is:.WORD 0x000D, 0x1858, 0xFA01, 0x0040 (base-address = load-address + file-offset)•For the ring3 stack (not part of ELF file):.WORD 0x0FFF, 0x2100, 0xF201, 0x0040Task-State Segment•Because the system-calls (via int 0x80) will cause privilege-level transitions, we will need to setup a Task-State Segment (to store the ring0 stacktop pointer) theTSS: .WORD 0, 0, 0 ; 3 longwords•Its segment-descriptor goes into our GDT: .WORD 0x000B, theTSS, 0x8901, 0x0000Transition to Ring 3•Recall that we use ‘retf’ to enter ring 3:push word #userSSpush word #0x1000push word #userCSpush word #0x0000retfSystem-Call Dispatcher•All system-calls are ‘vectored’ through IDT interrupt-gate 0x80 •For ‘hello.o’ we only require implementing two system-calls: ‘exit’ and ‘write’•But to simplify future enhancements, we used a ‘jump-table’ anyway (for now it has a few ‘dummy’ entries that we can modify later)System-Call ID-numbers•System-call ID #0 (it will never be needed)•System-call ID #1 is for ‘exit’ (required)•System-call ID #2 is for ‘fork’ (deferred)•System-call ID #3 is for ‘read’ (deferred)•System-call ID #4 is for ‘write’ (required)•System-call ID #5 is for ‘open’ (deferred)•System-call ID #6
View Full Document