1 /** 2 * Written in the D programming language. 3 * This module provides Darwin 64 bit specific support for sections. 4 * 5 * Copyright: Copyright Digital Mars 2016. 6 * License: Distributed under the 7 * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). 8 * (See accompanying file LICENSE) 9 * Authors: Jacob Carlborg 10 * Source: $(DRUNTIMESRC rt/_sections_darwin_64.d) 11 */ 12 module rt.sections_darwin_64; 13 14 version (OSX) 15 version = Darwin; 16 else version (iOS) 17 version = Darwin; 18 else version (TVOS) 19 version = Darwin; 20 else version (WatchOS) 21 version = Darwin; 22 23 version (Darwin): 24 version (D_LP64): 25 26 import core.sys.darwin.mach.dyld; 27 import core.sys.darwin.mach.getsect; 28 import core.sys.posix.pthread; 29 30 import rt.util.utility : safeAssert; 31 32 extern (C) size_t malloc_size(const void* ptr) nothrow @nogc; 33 34 /** 35 * Returns the TLS range of the image containing the specified TLS symbol, 36 * or null if none was found. 37 */ 38 void[] getTLSRange(const void* tlsSymbol) nothrow @nogc 39 { 40 foreach (i ; 0 .. _dyld_image_count) 41 { 42 const header = cast(const(mach_header_64)*) _dyld_get_image_header(i); 43 auto tlvInfo = tlvInfo(header); 44 45 if (tlvInfo.foundTLSRange(tlsSymbol)) 46 return tlvInfo.tlv_addr[0 .. tlvInfo.tlv_size]; 47 } 48 49 return null; 50 } 51 52 /** 53 * Returns `true` if the correct TLS range was found. 54 * 55 * If the given `info` is located in the same image as the given `tlsSymbol` 56 * this will return `true`. 57 * 58 * Params: 59 * info = the TLV info containing the TLV base address 60 * tlsSymbol = the TLS symbol to search for 61 * 62 * Returns: `true` if the correct TLS range was found 63 */ 64 bool foundTLSRange(const ref dyld_tlv_info info, const void* tlsSymbol) pure nothrow @nogc 65 { 66 return info.tlv_addr <= tlsSymbol && 67 tlsSymbol < (info.tlv_addr + info.tlv_size); 68 } 69 70 71 /// TLV info. 72 struct dyld_tlv_info 73 { 74 /// sizeof(dyld_tlv_info) 75 size_t info_size; 76 77 /// Base address of TLV storage 78 void* tlv_addr; 79 80 /// Byte size of TLV storage 81 size_t tlv_size; 82 } 83 84 /** 85 * Returns the TLV info for the given image. 86 * 87 * Params: 88 * header = the image to look for the TLV info in 89 * 90 * Returns: the TLV info 91 */ 92 dyld_tlv_info tlvInfo(const mach_header_64* header) nothrow @nogc 93 { 94 const key = header.firstTLVKey; 95 auto tlvAddress = key == pthread_key_t.max ? null : pthread_getspecific(key); 96 97 dyld_tlv_info info = { 98 info_size: dyld_tlv_info.sizeof, 99 tlv_addr: tlvAddress, 100 tlv_size: tlvAddress ? malloc_size(tlvAddress) : 0 101 }; 102 103 return info; 104 } 105 106 /** 107 * Returns the first TLV key for the given image. 108 * 109 * The TLV key is a key that associates a value of type `dyld_tlv_info` with a 110 * thread. Each thread local variable has an associates TLV key. The TLV keys 111 * are all the same for each image. 112 * 113 * Params: 114 * header = the image to look for the TLV key in 115 * 116 * Returns: the first TLV key for the given image or `pthread_key_t.max` if no 117 * key was found. 118 */ 119 pthread_key_t firstTLVKey(const mach_header_64* header) pure nothrow @nogc 120 { 121 intptr_t slide = 0; 122 bool slideComputed = false; 123 const size = mach_header_64.sizeof; 124 auto command = cast(const(load_command)*)(cast(ubyte*) header + size); 125 126 foreach (_; 0 .. header.ncmds) 127 { 128 if (command.cmd == LC_SEGMENT_64) 129 { 130 auto segment = cast(const segment_command_64*) command; 131 132 if (!slideComputed && segment.filesize != 0) 133 { 134 slide = cast(uintptr_t) header - segment.vmaddr; 135 slideComputed = true; 136 } 137 138 foreach (const ref section; segment.sections) 139 { 140 if ((section.flags & SECTION_TYPE) != S_THREAD_LOCAL_VARIABLES) 141 continue; 142 143 return section.firstTLVDescriptor(slide).key; 144 } 145 } 146 147 command = cast(const(load_command)*)(cast(ubyte*) command + command.cmdsize); 148 } 149 150 return pthread_key_t.max; 151 } 152 153 /** 154 * Returns the first TLV descriptor of the given section. 155 * 156 * Params: 157 * section = the section to get the TLV descriptor from 158 * slide = the slide 159 * 160 * Returns: the TLV descriptor 161 */ 162 const(tlv_descriptor)* firstTLVDescriptor(const ref section_64 section, intptr_t slide) pure nothrow @nogc 163 { 164 return cast(const(tlv_descriptor)*)(section.addr + slide); 165 } 166 167 /** 168 * Returns the sections of the given segment. 169 * 170 * Params: 171 * segment = the segment to get the sections from 172 * 173 * Returns: the sections. 174 */ 175 const(section_64)[] sections(const segment_command_64* segment) pure nothrow @nogc 176 { 177 const size = segment_command_64.sizeof; 178 const firstSection = cast(const(section_64)*)(cast(ubyte*) segment + size); 179 return firstSection[0 .. segment.nsects]; 180 } 181 182 /// Invokes the specified delegate for each (non-empty) data section. 183 void foreachDataSection(in mach_header* header, intptr_t slide, 184 scope void delegate(void[] sectionData) processor) 185 { 186 foreach (section; [ SECT_DATA, SECT_BSS, SECT_COMMON ]) 187 { 188 auto data = getSection(header, slide, SEG_DATA.ptr, section.ptr); 189 if (data !is null) 190 processor(data); 191 } 192 } 193 194 /// Returns a section's memory range, or null if not found or empty. 195 void[] getSection(in mach_header* header, intptr_t slide, 196 in char* segmentName, in char* sectionName) 197 { 198 safeAssert(header.magic == MH_MAGIC_64, "Unsupported header."); 199 auto sect = getsectbynamefromheader_64(cast(mach_header_64*) header, 200 segmentName, sectionName); 201 202 if (sect !is null && sect.size > 0) 203 return (cast(void*)sect.addr + slide)[0 .. cast(size_t) sect.size]; 204 return null; 205 }