flat assembler
Message board for the users of flat assembler.
Index
> Unix > Mach-O executables made with fasmg Goto page 1, 2 Next |
Author |
|
Tomasz Grysztar 10 Aug 2017, 18:48
The further layer of macros is for the dynamic linking. This is a dangerous ground, the structures required for this are numerous and cross-reference each other, and on the top of that, recent versions of MacOS introduced an entirely new load commands (LC_DYLD) for this purpose. I have not yet touched these new commands (which appear to contain some kind of byte code interpreted by dylink), for now I tried to get the legacy ones to work.
First I tried the manual creation of symbol tables and dynamic linking structures: Code: include '80386.inc' use32 MachO.Settings.BaseAddress = 0x1000 include 'macho.inc' segment '__TEXT' readable executable section '__text' align 16 entry start start: and esp,0FFFFFFF0h sub esp,10h mov dword [esp],msg call printf and dword [esp],0 call exit section '__cstring' align 4 msg db 'Hello World!',0Ah,0 segment '__IMPORT' readable executable section '__nl_symbol_ptr' flags(S_NON_LAZY_SYMBOL_POINTERS) reserved1(0) __printf dd ? __exit dd ? section '__jump_table' flags(S_SYMBOL_STUBS+S_ATTR_SOME_INSTRUCTIONS+S_ATTR_PURE_INSTRUCTIONS) reserved1(0) reserved2(STUB_SIZE) printf: jmp dword [__printf] STUB_SIZE := $ - printf exit: jmp dword [__exit] segment '__LINKEDIT' readable symbols = $% ; msg dd str_msg ; n_strx db N_SECT ; n_type db 2 ; n_sect dw 0 ; n_desc dd msg ; n_value ; start dd str_start db N_SECT + N_EXT db 1 dw 0 dd start ; _printf dd str_printf db N_EXT db 0 dw REFERENCE_FLAG_UNDEFINED_NON_LAZY dd 0 ; _exit dd str_exit db N_EXT db 0 dw REFERENCE_FLAG_UNDEFINED_NON_LAZY dd 0 indirect = $% ; indexes into symbol table: dd 2 ; _printf dd 3 ; _exit strings = $% db ' ',0 str_msg = $% - strings db 'msg',0 str_start = $% - strings db 'start',0 str_printf = $% - strings db '_printf',0 str_exit = $% - strings db '_exit',0 strings_size = $% - strings MachO.command LC_LOAD_DYLINKER dd dylinker-MachO.COMMAND dylinker db '/usr/lib/dyld',0 align 4 MachO.command LC_LOAD_DYLIB dd dylib-MachO.COMMAND dd 2 ; timestamp dd 0x006F0103 ; currentver dd 0x00010000 ; compatver dylib db '/usr/lib/libSystem.B.dylib',0 align 4 MachO.command LC_SYMTAB dd symbols ; symoff dd 4 ; nsyms dd strings ; stroff dd strings_size ; strsize MachO.command LC_DYSYMTAB ; one local symbol (msg): dd 0 ; ilocalsym dd 1 ; nlocalsym ; one public symbol (start): dd 1 ; iextdefsym dd 1 ; nextdefsym ; two external symbols (printf, exit): dd 2 ; iundefsym dd 2 ; nundefsym dd 0 ; tocoff dd 0 ; ntoc dd 0 ; modtaboff dd 0 ; nmodtab dd 0 ; extrefsymoff dd 0 ; nextrefsyms ; all external symbols are linked indirectly: dd indirect ; indirectsymoff dd 2 ; nindirectsyms dd 0 ; extreloff dd 0 ; nextrel dd 0 ; locreloff dd 0 ; nlocrel The macros I made for dynamic linking use the non-lazy pointers like the above sample: Code: ; Upper layer: dynamic linking namespace MachO NSYMS = 0 LIB_NUMBER = 0 end namespace macro interpreter? path MachO.command LC_LOAD_DYLINKER namespace MachO.dylinker_command lc_str dd dylinker-MachO.COMMAND dylinker db path,0 align 4 end namespace end macro macro uses? lib& MachO.LIB_NUMBER = MachO.LIB_NUMBER + 1 MachO.command LC_LOAD_DYLIB repeat 1, l:MachO.LIB_NUMBER namespace MachO.dylib#l#_command lc_str dd dylib-MachO.COMMAND timestamp dd 2 match path (a.b.c=,x.y.z), lib current_version dd (x and 0FFFFh) shl 16 + y shl 8 + z compatibility_version dd (a and 0FFFFh) shl 16 + b shl 8 + c dylib db path,0 else current_version dd 10000h compatibility_version dd 10000h dylib db lib,0 end match align 4 end namespace end repeat end macro macro import? definitions& iterate <name,string>, definitions MachO.NSYMS = MachO.NSYMS + 1 define MachO.symbol name name.extrn := 1 name.type := N_EXT name.desc := REFERENCE_FLAG_UNDEFINED_NON_LAZY define name.str string end iterate end macro postpone if MachO.NSYMS segment '__IMPORT' readable writable executable section '__nl_symbol_ptr' flags(S_NON_LAZY_SYMBOL_POINTERS) reserved1(0) align 4 irpv sym, MachO.symbol if sym.extrn if MachO.CPUTYPE and CPU_ARCH_ABI64 sym.ptr dq ? else sym.ptr dd ? end if end if end irpv section '__jump_table' flags(S_SYMBOL_STUBS+S_ATTR_SOME_INSTRUCTIONS+S_ATTR_PURE_INSTRUCTIONS) reserved1(0) reserved2(MachO.JUMP_SIZE) align 16 irpv sym, MachO.symbol if sym.extrn sym: jmp [sym.ptr] if % = 1 MachO.JUMP_SIZE := $ - sym end if end if end irpv segment '__LINKEDIT' readable MachO.SYMOFF := $% irpv sym, MachO.symbol namespace MachO.nlist#% n_strx dd sym.strx n_type db sym.type n_sect db 0 n_desc dw sym.desc if MachO.CPUTYPE and CPU_ARCH_ABI64 n_value dq sym else n_value dd sym end if end namespace end irpv MachO.INDIRECTSYMOFF := $% irpv sym, MachO.symbol if sym.extrn dd %-1 end if end irpv MachO.STROFF := $% db 20h,0 irpv sym, MachO.symbol sym.strx := $% - MachO.STROFF db string sym.str, 0 end irpv MachO.STRSIZE := $% - MachO.STROFF MachO.command LC_SYMTAB namespace MachO.symtab_command symoff dd SYMOFF nsyms dd NSYMS stroff dd STROFF strsize dd STRSIZE end namespace MachO.command LC_DYSYMTAB namespace MachO.dysymtab_command ilocalsym dd 0 nlocalsym dd 0 iextdefsym dd 0 nextdefsym dd 0 iundefsym dd 0 nundefsym dd NSYMS tocoff dd 0 ntoc dd 0 modtaboff dd 0 nmodtab dd 0 extrefsymoff dd 0 nextrefsyms dd 0 indirectsymoff dd INDIRECTSYMOFF nindirectsyms dd NSYMS extreloff dd 0 nextrel dd 0 locreloff dd 0 nlocrel dd 0 end namespace end if end postpone Code: include '80386.inc' use32 MachO.Settings.BaseAddress = 0x1000 include 'macho.inc' interpreter '/usr/lib/dyld' uses '/usr/lib/libSystem.B.dylib' (1.0.0, 1225.0.0) import printf,'_printf',\ exit,'_exit' segment '__TEXT' readable executable section '__text' align 16 entry start start: and esp,0FFFFFFF0h sub esp,10h mov dword [esp],msg call printf and dword [esp],0 call exit section '__cstring' align 4 msg db 'Hello World!',0Ah,0 |
|||
10 Aug 2017, 18:48 |
|
Tomasz Grysztar 10 Aug 2017, 19:06
I'm attaching the complete set of macros I have made so far, packaged with a few examples.
I was not able to get working 64-bit executable with dynamic linking, it needs an additional investigation. If you find any way to correct or improve these macros, please let me know.
|
|||||||||||
10 Aug 2017, 19:06 |
|
Tomasz Grysztar 10 Aug 2017, 21:07
Finally, the above macros can be used to assemble fasmg itself as a dynamically linked Mach-O executable. I'm attaching a pre-assembled executable and the source files that need to be added to the standard "source" directory of fasmg.
EDIT: this is now included in the official fasmg packaging. Last edited by Tomasz Grysztar on 26 Aug 2017, 15:42; edited 2 times in total |
|||
10 Aug 2017, 21:07 |
|
ProMiNick 10 Aug 2017, 21:46
fasmg sources not full:
Code: flat assembler version g.hvj4j C:\FASM\SOURCE_G\fasmg_macos\fasmg.asm [66]: or al,TRACE_ERROR_STACK macro or [2] macro parse_operand [10] macro parse_operand_value [31]: ns.imm = +op Processed: @src.imm = +TRACE_ERROR_STACK Error: symbol 'TRACE_ERROR_STACK' is undefined or out of scope. pushes & popes in machO - cancelled? Why so strange ccall? |
|||
10 Aug 2017, 21:46 |
|
Tomasz Grysztar 10 Aug 2017, 21:57
ProMiNick wrote: fasmg sources not full: |
|||
10 Aug 2017, 21:57 |
|
ProMiNick 10 Aug 2017, 22:24
Yes. All compiled OK.
What about ccall? pushes? why moves to [esp...] used? |
|||
10 Aug 2017, 22:24 |
|
Tomasz Grysztar 11 Aug 2017, 09:47
ProMiNick wrote: What about ccall? pushes? why moves to [esp...] used? PS I have updated the macros above with a few small fixes. |
|||
11 Aug 2017, 09:47 |
|
tthsqe 11 Aug 2017, 15:32
Oh thank you Tomasz! I just went through the trouble of using objconv.
Some questions: If I port the code reasonably from fasm to fasmg, will fasmg produce identical binaries? Does fasmg do all of the size optimisations that fasm does? |
|||
11 Aug 2017, 15:32 |
|
Tomasz Grysztar 11 Aug 2017, 16:13
tthsqe wrote: If I port the code reasonably from fasm to fasmg, will fasmg produce identical binaries? Does fasmg do all of the size optimisations that fasm does? Of course it is also possible that there may be some alternative macro sets implementing x86 in the future. I think someone on the board worked on one already. A less complex one could be made to allow faster assembly (though there may be not much to gain, implementation of instructions as macros is going to be relatively slow by its very nature). On the opposite end of spectrum, I started working on even more complex macros that demonstrate some of the ideas I had for fasm 2 (before I decided to reduce my fasm 2 project to just fasmg). |
|||
11 Aug 2017, 16:13 |
|
tthsqe 11 Aug 2017, 16:32
I will give porting my source from fasm to fasmg a shot then. BTW, I know how much trouble it is to get documentation on apple's suff. Any they change things from version to version.
|
|||
11 Aug 2017, 16:32 |
|
tthsqe 12 Aug 2017, 07:38
I noticed that your mach-o macros don't contain anything resembling relocations. Could I get confirmation/disconfirmation of the following concerning the code at the end?
0. In any format: The d address in f is encoded as rip-relative since fasm knows the sizes of the sections. 1. In format PE64: The d address in g cannot be encoded as rip-relative by an architecture constraint. In the dword field of the encoding, fasm puts the absolute address of d since the absolute address of the base of the module is known. If the absolute address of d cannot be encoded as a dword, an error occurs. 2. In format PE64 with fixups: The d address in g is encoded using an assumed absolute address (p) of the base of the module. If the OS decides to load the module at another address (q), then "data fixups; end data" contains the locations of the dwords/qwords that need to be shifted by q-p. If any of these operations overflows, an error occurs. 3. In format ELF64: The d address in g is encoded using "dd ?". When the OS loads the module at some address (p), then the relocation section contains the locations of the dwords/qwords that need to modified based on the value of p. If any of these operations overflows, an error occurs. 4. In format MACH-O: Much the same as "format PE64"? Of course MACH-O has some relocation scheme so that dynamically linked libraries are possible? Code: ...[some section]... f: mov eax, dword[d] ret g: xor eax, eax mov eax, dword[d+rax] ret ...[another section]... d: dd 42 |
|||
12 Aug 2017, 07:38 |
|
Tomasz Grysztar 12 Aug 2017, 14:09
tthsqe wrote: I noticed that your mach-o macros don't contain anything resembling relocations. tthsqe wrote: Could I get confirmation/disconfirmation of the following concerning the code at the end? All of the three PE/COFF, ELF, and Mach-O formats have both the executable and object variant (in case of PE/COFF the executable variant is PE and the object variant is COFF). The executable variant is always an image assembled with a fixed memory layout and an assumed base address. Optionally the image may allow to be loaded at different address, either because it is position-independent or because it has fixups that can be applied to correct the addresses in code when the base shifts. Only PE format has the ability to contain fixups, in case of ELF and Mach-O if the executable is to allow being loaded at different base, in needs to be PIC. All of the executable formats also allow dynamic linking, which involves resolving some external symbols and placing their addresses in a special data table in the executable image. Most of the time these are the addresses of external functions, and calling these functions can be done either though an indirect call to the field in the dynamic linking table: Code: call [__exit] Code: call exit ; ... exit: jmp [_exit] As for the object formats, they always have true relocations. tthsqe wrote: 0. In any format: Second: even RIP-relative addressing may still require relocation, when the output is a relocatable object and f and d reside in different sections. In the process of linking the sections may end up at different distance from each other and relative addressing still requires relocation. This applies to RIP-relative data addressing, and to the relative jumps/calls as well. tthsqe wrote: 1. In format PE64: tthsqe wrote: 2. In format PE64 with fixups: tthsqe wrote: 3. In format ELF64: In general Mach-O format capabilities are similar to ELF - the executable variant allows dynamic linking (this includes things like GOT for PIC) but no fixups, the object variant has true relocations. All the examples I created so far are executables (with MH_EXECUTABLE type in header), but you could use the same low-layer macros to create an object file. You'd need to alter some fields in the header with settings like: Code: MachO.Settings.FileType equ MH_OBJECT MachO.Settings.Flags = 0 |
|||
12 Aug 2017, 14:09 |
|
tthsqe 21 Aug 2017, 08:14
Thomas, your 64 macros don't work for dynamic linking.
I have attached the binary of a working executable as well as some of its info with objconv. Your macros are missing a few sections as well as the trampoline instructions for the dynamic loader. This program calls write then exit. In the program, "write" and "exit" are calls to jmp instructions in the ._TEXT.__stubs section. Each of these jumps fetches an address from the ._DATA.__la_symbol_ptr section. Initially, these address in the ._DATA.__la_symbol_ptr point to something like Code: push N jmp ?_004 where ?_004 is the address of the thing that calls imp_dyld_stub_binder. If you look in the binary, your will see strings "@_exit" and "@_write" in this order. The "N" is the offset of function name from the first name (@_exit). As for how imp_dyld_stub_binder knows where to write the address of the found function to the ._DATA.__la_symbol_ptr section, I have no idea. (I am fairly certain that imp_dyld_stub_binder will overwrite these addresses so that it is not called the next time the imported function with this name is called). Also, objconv completed with some error, so the human readable form might not be complete. I have been reading http://timetobleed.com/dynamic-linking-elf-vs-mach-o/ Code: ; Disassembly of file: mac_test ; Mode: 64 bits ; Syntax: YASM/NASM ; Instruction set: 8086, x64 default rel global __mh_execute_header global _main extern dyld_stub_binder ; byte extern _write ; byte extern _exit ; byte SECTION ._TEXT._code align=64 execute ; section number 1, code _main: ; Function begin and rsp, 0FFFFFFFFFFFFFFF0H ; 0F40 _ 48: 83. E4, F0 mov edi, 1 ; 0F44 _ BF, 00000001 lea rsi, [rel ?_001] ; 0F49 _ 48: 8D. 35, 00000011(rel) mov edx, 13 ; 0F50 _ BA, 0000000D call ?_003 ; 0F55 _ E8, 0000001A(rel) mov eax, edi ; 0F5A _ 89. F8 call ?_002 ; 0F5C _ E8, 0000000D(rel) ?_001: ; Error: Prefix after REX prefix not allowed ; Note: Prefix bit or byte has no meaning in this context ; insb ; 0F61 _ 48 65: 6C db 48H, 65H, 6CH ; insb ; 0F64 _ 6C db 6CH ; outsd ; 0F65 _ 6F db 6FH ; and byte [rdi+6FH], dl ; 0F66 _ 20. 57, 6F db 20H, 57H, 6FH ; jc 97H ; 0F69 _ 72, 6C db 72H, 6CH ; Note: Function does not end with ret or jmp ; and dword [fs:rdx], ecx ; 0F6B _ 64: 21. 0A db 64H, 21H, 0AH ; _main End of function SECTION ._TEXT.__stubs align=2 execute ; section number 2, code ?_002: ; Local function jmp near [rel ?_005] ; 0F6E _ FF. 25, 0000009C(rel) ?_003: ; Local function jmp near [rel ?_006] ; 0F74 _ FF. 25, 0000009E(rel) SECTION ._TEXT.__stub_helper align=4 execute ; section number 3, code ?_004: ; Local function lea r11, [rel imp__exit] ; 0F7C _ 4C: 8D. 1D, 00000085(rel) push r11 ; 0F83 _ 41: 53 jmp near [rel imp_dyld_stub_binder] ; 0F85 _ FF. 25, 00000075(rel) nop ; 0F8B _ 90 ; Note: Immediate operand could be made smaller by sign extension push 0 ; 0F8C _ 68, 00000000 ; Note: Immediate operand could be made smaller by sign extension jmp ?_004 ; 0F91 _ E9, FFFFFFE6 ; Note: Immediate operand could be made smaller by sign extension push 12 ; 0F96 _ 68, 0000000C ; Note: Immediate operand could be made smaller by sign extension jmp ?_004 ; 0F9B _ E9, FFFFFFDC SECTION ._TEXT.__unwind_info align=4 noexecute ; section number 4, data db 01H, 00H, 00H, 00H, 1CH, 00H, 00H, 00H ; 0FA0 _ ........ db 00H, 00H, 00H, 00H, 1CH, 00H, 00H, 00H ; 0FA8 _ ........ db 00H, 00H, 00H, 00H, 1CH, 00H, 00H, 00H ; 0FB0 _ ........ db 02H, 00H, 00H, 00H, 40H, 0FH, 00H, 00H ; 0FB8 _ ....@... db 34H, 00H, 00H, 00H, 34H, 00H, 00H, 00H ; 0FC0 _ 4...4... db 6FH, 0FH, 00H, 00H, 00H, 00H, 00H, 00H ; 0FC8 _ o....... db 34H, 00H, 00H, 00H, 03H, 00H, 00H, 00H ; 0FD0 _ 4....... db 0CH, 00H, 01H, 00H, 10H, 00H, 01H, 00H ; 0FD8 _ ........ db 00H, 00H, 00H, 00H, 00H, 00H, 00H, 00H ; 0FE0 _ ........ SECTION ._DATA.__nl_symbol_ptr align=8 noexecute ; section number 5, data imp_dyld_stub_binder: ; import from ? dq 0000000000000000H ; 1000 _ 0000000000000000 imp__exit: ; dword dd 00000000H ; 1008 _ 0 imp__write: ; dword dd 00000000H ; 100C _ 0 SECTION ._DATA.__la_symbol_ptr align=8 noexecute ; section number 6, data ?_005: ; switch/case jump table dq 0000000100000F8CH ; 1010 _ 0000000100000F8C ?_006: ; switch/case jump table dq 0000000100000F96H ; 1018 _ 0000000100000F96 Code: Dump of file: mac_test, type: Mach-O Little Endian64 Dump of Mach-O file mac_test ----------------------------------------------- File size: 0x2120 File header: CPU type: Intel 64 bit, subtype: unknown(0x80000003) File type: Mach-O Little Endian - demand paged executable file Number of load commands: 15, Size of commands: 0x460, Flags: 200085 Command 1: 64-bit segment, size: 0x48 Name: __PAGEZERO, Memory address 0x0000000000000000, Memory size 0x0000000100000000 File offset 0x0000000000000000, File size 0x0000000000000000 Maxprot 0x0, Initprot 0x0 Number of sections 0, Flags 0x0 Command 2: 64-bit segment, size: 0x188 Name: __TEXT, Memory address 0x0000000100000000, Memory size 0x0000000000001000 File offset 0x0000000000000000, File size 0x0000000000001000 Maxprot 0x7, Initprot 0x5 Number of sections 4, Flags 0x0 Command 3: 64-bit segment, size: 0xE8 Name: __DATA, Memory address 0x0000000100001000, Memory size 0x0000000000001000 File offset 0x0000000000001000, File size 0x0000000000001000 Maxprot 0x7, Initprot 0x3 Number of sections 2, Flags 0x0 Command 4: 64-bit segment, size: 0x48 Name: __LINKEDIT, Memory address 0x0000000100002000, Memory size 0x0000000000001000 File offset 0x0000000000002000, File size 0x0000000000000120 Maxprot 0x7, Initprot 0x1 Number of sections 0, Flags 0x0 Command 5: unknown(0x80000022), size: 0x30 Command 6: Symbol table, size: 0x18 Symbol table offset 0x2078, number of symbols 5, String table offset 0x20E0, String table size 0x40 Command 7: dynamic link-edit symbol table info, size: 0x50 Index to local symbols 0, number of local symbols 0, Index to external symbols 0, number of external symbols 2, Index to undefined symbols 2, number of undefined symbols 3, File offset to TOC 0x0, number of entries in TOC 0, File offset to module table 0x0, Number of module table entries 0, Offset to referenced symbol table 0x0, Number of referenced symtab entries 0 Offset to indirect symbol table 0x20C8, Number of indirect symtab entries 6 Offset to external relocation entries 0x0, Number of external reloc. entries 0 Offset to local relocation entries 0x0, Number of local reloc. entries 0 Command 8: load a dynamic linker, size: 0x20 Command 9: uuid, size: 0x18 Command 10: unknown(0x24), size: 0x10 Command 11: unknown(0x2A), size: 0x10 Command 12: unknown(0x80000028), size: 0x18 Command 13: load a dynamicly linked shared library, size: 0x38 Command 14: unknown(0x26), size: 0x10 Command 15: unknown(0x29), size: 0x10 Sections: Section 1: Name: _code, Segment: __TEXT. Memory address 0xF40, Size 0x2E, File offset 0xF40 Alignment 64, Reloc. ent. offset 0x0, Num reloc. 0 Flags 0x80000400, reserved1 0x0, reserved2 0x0 Section 2: Name: __stubs, Segment: __TEXT. Memory address 0xF6E, Size 0xC, File offset 0xF6E Alignment 2, Reloc. ent. offset 0x0, Num reloc. 0 Flags 0x80000408, reserved1 0x0, reserved2 0x6 Section 3: Name: __stub_helper, Segment: __TEXT. Memory address 0xF7C, Size 0x24, File offset 0xF7C Alignment 4, Reloc. ent. offset 0x0, Num reloc. 0 Flags 0x80000400, reserved1 0x0, reserved2 0x0 Section 4: Name: __unwind_info, Segment: __TEXT. Memory address 0xFA0, Size 0x48, File offset 0xFA0 Alignment 4, Reloc. ent. offset 0x0, Num reloc. 0 Flags 0x0, reserved1 0x0, reserved2 0x0 Section 5: Name: __nl_symbol_ptr, Segment: __DATA. Memory address 0x1000, Size 0x10, File offset 0x1000 Alignment 8, Reloc. ent. offset 0x0, Num reloc. 0 Flags 0x6, reserved1 0x2, reserved2 0x0 Section 6: Name: __la_symbol_ptr, Segment: __DATA. Memory address 0x1010, Size 0x10, File offset 0x1010 Alignment 8, Reloc. ent. offset 0x0, Num reloc. 0 Flags 0x7, reserved1 0x4, reserved2 0x0 Symbol table: Public symbols: 0 __mh_execute_header, Section 1, Value 0x0 External, Defined Reference type: External non lazy, Flags: Referenced dynamically, 1 _main, Section 1, Value 0xF40 External, Defined Reference type: External non lazy, Flags: External symbols: 2 _exit, Section 0, Value 0x0 External, Undefined, no section Reference type: External non lazy, Flags: 3 _write, Section 0, Value 0x0 External, Undefined, no section Reference type: External non lazy, Flags: 4 dyld_stub_binder, Section 0, Value 0x0 External, Undefined, no section Reference type: External non lazy, Flags: Indirect symbols: _exit, type 0x1, sect 0, desc 0x100, val 0x0 _write, type 0x1, sect 0, desc 0x100, val 0x0 dyld_stub_binder, type 0x1, sect 0, desc 0x100, val 0x0 Unknown(0x40000000) _exit, type 0x1, sect 0, desc 0x100, val 0x0 _write, type 0x1, sect 0, desc 0x100, val 0x0 String table: 0: 2: __mh_execute_header 22: _main 28: _exit 34: _write 41: dyld_stub_binder 58: 59: 60: 61: 62: 63:
|
|||||||||||
21 Aug 2017, 08:14 |
|
Tomasz Grysztar 21 Aug 2017, 10:51
tthsqe wrote: Thomas, your 64 macros don't work for dynamic linking. The "lazy" externals require additional "trampolines" as you mentioned, but I did not find out what makes them tick (I like to know exactly how things work and then make the absolutely minimal implementation). Each stub (the one that consists only of a single JMP instruction) has to initially jump to the trampoline, and that code in turn has to call the dynamic linker somehow, and provide the parameters (in registers?) telling what function needs to have it address resolved and updated in the stub - this is the part I have not yet figured out. It make take some time before a have a chance to work on it more - if you find out anything in the meantime, please let me know. |
|||
21 Aug 2017, 10:51 |
|
tthsqe 21 Aug 2017, 13:54
Ok. This is probably take a long time to work out. I can see right away that for 64bits, your macros are generating jmp instructions in a __jmp_table section. It looks like the way it is done is to put a "dq ?" in the __DATA,__nl_symbol_ptr section.
I'm reading https://www.mikeash.com/pyblog/friday-qa-2012-11-09-dyld-dynamic-linking-on-os-x.html |
|||
21 Aug 2017, 13:54 |
|
redsock 21 Aug 2017, 21:23
I attempted to create a VirtualBox guest out of macOS Sierra yesterday to put up, the VM gets stuck waiting on the root device though so I was unable to finish.
Didn't have a ton of time to research, but if any of you have ideas to get me past that point I can donate another macOS VM to play around with. |
|||
21 Aug 2017, 21:23 |
|
Tomasz Grysztar 22 Aug 2017, 19:33
tthsqe wrote: Ok. This is probably take a long time to work out. I can see right away that for 64bits, your macros are generating jmp instructions in a __jmp_table section. It looks like the way it is done is to put a "dq ?" in the __DATA,__nl_symbol_ptr section. Code: _exit dq ? ; DD in 32-bit case Code: call [_exit] Code: call exit ; ... exit: ; stub jmp [_exit] OK, we now have non-lazy binding covered, not let's talk about the lazy one, which may actually be necessary for the functions in 64-bit Mach-O (though this is just my theory at the moment). In this case dynamic linker does not fill the import variables with pointers to the functions. These variables should be pre-filled at the assembly time with pointers to the "stub helpers": Code: _exit dq _exit.helper _exit.helper: ; some code that calls dynamic linker and tells it to update [_exit] with a pointer to the external function, and then jump there Now the detail I was missing when I wanted to change my macros from non-lazy binding to a lazy one is what that stub helper should do, exactly (in both 32-bit and 64-bit variants) and how can it call the dynamic linker. |
|||
22 Aug 2017, 19:33 |
|
Grom PE 23 Aug 2017, 05:15
redsock wrote: I attempted to create a VirtualBox guest out of macOS Sierra yesterday to put up, the VM gets stuck waiting on the root device though so I was unable to finish. But an image of macOS Sierra didn't want to cooperate — it crashed (rebooted) in minutes after any nontrivial action, and fasmg and related binaries gave an error "Illegal Instruction: 4" on it. I'm not sure if I got a broken image of Sierra or its loader is more strict and something is missing. Or maybe something to do with the fact I'm trying this on AMD processor. |
|||
23 Aug 2017, 05:15 |
|
tthsqe 23 Aug 2017, 07:19
Thomasz, there is the source I am using.
Code: include 'x86/include/x64.inc' use64 MachO.Settings.ProcessorType equ CPU_TYPE_X86_64 MachO.Settings.BaseAddress = 0x100000000 include 'x86/macinc/macho.inc' entry Start interpreter '/usr/lib/dyld' uses '/usr/lib/libSystem.B.dylib' (1.0.0, 1.0.0) import _write,'_write' import _exit,'_exit' segment '__TEXT' readable executable Start: and rsp, -16 mov edi, 1 lea rsi, [msg] mov edx, msg_end - msg call _write mov edi, eax call _exit msg: db 'Hello World!',10 msg_end: your current macros are generating something like this Code: segment '__TEXT' readable executable Start: and rsp, -16 mov edi, 1 lea rsi, [msg] mov edx, msg_end - msg call _write mov edi, eax call _exit msg: db 'Hello World!',10 msg_end: segment '__IMPORT' readable writable executable section '__nl_symbol_ptr' _write2: dq ? _exit2: dq ? section '__jump_table' _write: jmp qword[_write2] _exit: jmp qword[_exit2] The problem with this is that dyld is going to have to write the correct addresses into qword[_write2] and qword[_exit2]. But this segment is marked executable. I though this was a big no-no. This might explain why your current macros generate exe's that segfault in dyld. From what I can tell you have to do something like this Code: segment '__TEXT' readable executable Start: and rsp, -16 mov edi, 1 lea rsi, [msg] mov edx, msg_end - msg call qword[_write] mov edi, eax call qword[_exit] msg: db 'Hello World!',10 msg_end: segment '__DATA' readable writable section '__nl_symbol_ptr' _write: dq ? _exit: dq ? and direct dyld to fill in qword[_write] and qword[_exit] |
|||
23 Aug 2017, 07:19 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2024, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.