Zig 0.17.0-dev (Split by item)

Shortcut keys
?
Show these tips
S
Focus search field
Esc
Clear focus & close tips
U
Jump to source code
↑
Move up in search results
↓
Move down in search results
↵
Go to active search result
This is an example of documentation generated by ZigDoc, an alternative to Zig's built-in Auto Doc feature. See also examples in other modes/formats. The project being documented here (as the example) is the Zig standard library. Public Function

open

Public Function
std.dynamic_library.ElfDynLib.open
pub fn open(path: []const u8, LD_LIBRARY_PATH: ?[]const u8) Error!ElfDynLib

Trusts the file. Malicious file will be able to execute arbitrary code.

Params

  • path: []const u8
  • LD_LIBRARY_PATH: ?[]const u8

File

dynamic_library.zig:224
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
    pub fn open(path: []const u8, LD_LIBRARY_PATH: ?[]const u8) Error!ElfDynLib {
        const io = std.Options.debug_io;

        const file = try resolveFromName(io, path, LD_LIBRARY_PATH);
        defer file.close(io);

        const stat = try file.stat(io);
        const size = std.math.cast(usize, stat.size) orelse return error.FileTooBig;

        const page_size = std.heap.pageSize();

        // This one is to read the ELF info. We do more mmapping later
        // corresponding to the actual LOAD sections.
        const file_bytes = try posix.mmap(
            null,
            mem.alignForward(usize, size, page_size),
            .{ .READ = true },
            .{ .TYPE = .PRIVATE },
            file.handle,
            0,
        );
        defer posix.munmap(file_bytes);

        const eh = @as(*elf.Ehdr, @ptrCast(file_bytes.ptr));
        if (!mem.eql(u8, eh.e_ident[0..4], elf.MAGIC)) return error.NotElfFile;
        if (eh.e_type != elf.ET.DYN) return error.NotDynamicLibrary;

        const elf_addr = @intFromPtr(file_bytes.ptr);

        // Iterate over the program header entries to find out the
        // dynamic vector as well as the total size of the virtual memory.
        var maybe_dynv: ?[*]usize = null;
        var virt_addr_end: usize = 0;
        {
            var i: usize = 0;
            var ph_addr: usize = elf_addr + eh.e_phoff;
            while (i < eh.e_phnum) : ({
                i += 1;
                ph_addr += eh.e_phentsize;
            }) {
                const ph = @as(*elf.ElfN.Phdr, @ptrFromInt(ph_addr));
                switch (ph.type) {
                    .LOAD => virt_addr_end = @max(virt_addr_end, ph.vaddr + ph.memsz),
                    .DYNAMIC => maybe_dynv = @as([*]usize, @ptrFromInt(elf_addr + ph.offset)),
                    else => {},
                }
            }
        }
        const dynv = maybe_dynv orelse return error.MissingDynamicLinkingInformation;

        // Reserve the entire range (with no permissions) so that we can do MAP.FIXED below.
        const all_loaded_mem = try posix.mmap(
            null,
            virt_addr_end,
            .{},
            .{ .TYPE = .PRIVATE, .ANONYMOUS = true },
            -1,
            0,
        );
        errdefer posix.munmap(all_loaded_mem);

        const base = @intFromPtr(all_loaded_mem.ptr);

        // Now iterate again and actually load all the program sections.
        {
            var i: usize = 0;
            var ph_addr: usize = elf_addr + eh.e_phoff;
            while (i < eh.e_phnum) : ({
                i += 1;
                ph_addr += eh.e_phentsize;
            }) {
                const ph = @as(*elf.ElfN.Phdr, @ptrFromInt(ph_addr));
                switch (ph.type) {
                    .LOAD => {
                        // The VirtAddr may not be page-aligned; in such case there will be
                        // extra nonsense mapped before/after the VirtAddr,MemSiz
                        const aligned_addr = (base + ph.vaddr) & ~(@as(usize, page_size) - 1);
                        const extra_bytes = (base + ph.vaddr) - aligned_addr;
                        const extended_memsz = mem.alignForward(usize, ph.memsz + extra_bytes, page_size);
                        const ptr = @as([*]align(std.heap.page_size_min) u8, @ptrFromInt(aligned_addr));
                        const prot = elfToProt(ph.flags);
                        _ = try posix.mmap(
                            ptr,
                            extended_memsz,
                            prot,
                            .{ .TYPE = .PRIVATE, .FIXED = true },
                            file.handle,
                            ph.offset - extra_bytes,
                        );
                    },
                    else => {},
                }
            }
        }

        var maybe_strings: ?[*:0]u8 = null;
        var maybe_syms: ?[*]elf.Sym = null;
        var maybe_hashtab: ?[*]posix.Elf_Symndx = null;
        var maybe_gnu_hash: ?*elf.gnu_hash.Header = null;
        var maybe_versym: ?[*]elf.Versym = null;
        var maybe_verdef: ?*elf.Verdef = null;

        {
            var i: usize = 0;
            while (dynv[i] != 0) : (i += 2) {
                const p = base + dynv[i + 1];
                switch (dynv[i]) {
                    elf.DT_STRTAB => maybe_strings = @ptrFromInt(p),
                    elf.DT_SYMTAB => maybe_syms = @ptrFromInt(p),
                    elf.DT_HASH => maybe_hashtab = @ptrFromInt(p),
                    elf.DT_GNU_HASH => maybe_gnu_hash = @ptrFromInt(p),
                    elf.DT_VERSYM => maybe_versym = @ptrFromInt(p),
                    elf.DT_VERDEF => maybe_verdef = @ptrFromInt(p),
                    else => {},
                }
            }
        }

        const hash_table: HashTable = if (maybe_gnu_hash) |gnu_hash|
            .{ .dt_gnu_hash = gnu_hash }
        else if (maybe_hashtab) |hashtab|
            .{ .dt_hash = hashtab }
        else
            return error.ElfHashTableNotFound;

        return .{
            .memory = all_loaded_mem,
            .strings = maybe_strings orelse return error.ElfStringSectionNotFound,
            .syms = maybe_syms orelse return error.ElfSymSectionNotFound,
            .hash_table = hash_table,
            .versym = maybe_versym,
            .verdef = maybe_verdef,
        };
    }