#include "stuff/align.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "stuff/errors.h"
#include "stuff/bytesex.h"
__private_extern__
uint32_t
guess_align(uint64_t vmaddr, uint32_t min, uint32_t max)
{
uint32_t align = max;
if (vmaddr)
{
uint64_t segalign = 1;
align = 0;
while((segalign & vmaddr) == 0)
{
segalign = segalign << 1;
align++;
}
align = align < min ? min : align;
align = align > max ? max : align;
}
return align;
}
__private_extern__
uint32_t
get_seg_align(struct mach_header *mhp,
struct mach_header_64 *mhp64,
struct load_command *load_commands,
enum bool swap_load_commands,
uint64_t size,
char *name)
{
uint32_t cur_align = MAXSEGALIGN;
uint32_t ncmds = mhp ? mhp->ncmds : mhp64->ncmds;
uint32_t sizeofcmds = mhp ? mhp->sizeofcmds : mhp64->sizeofcmds;
size_t sizeofhdr = mhp ? sizeof(*mhp) : sizeof(*mhp64);
uint32_t filetype = mhp ? mhp->filetype : mhp64->filetype;
if (sizeofcmds + sizeofhdr > size)
fatal("truncated or malformed object (load commands would "
"extend past the end of the file) in: %s", name);
if (mhp && mhp64)
fatal("internal error: file has both a 32-bit and 64-bit mach header:"
"%s", name);
struct load_command *lcp = load_commands;
enum byte_sex host_byte_sex = get_host_byte_sex();
for(uint32_t i = 0; i < ncmds; ++i)
{
uint32_t align = MAXSEGALIGN;
struct load_command l = *lcp;
if(swap_load_commands)
swap_load_command(&l, host_byte_sex);
if(l.cmdsize % sizeof(uint32_t) != 0)
error("load command %u size not a multiple of "
"sizeof(uint32_t) in: %s", i, name);
if(l.cmdsize <= 0)
fatal("load command %u size is less than or equal to zero "
"in: %s", i, name);
if((char *)lcp + l.cmdsize >
(char *)load_commands + sizeofcmds)
fatal("load command %u extends past end of all load "
"commands in: %s", i, name);
if(l.cmd == LC_SEGMENT)
{
struct segment_command* sgp = (struct segment_command *)lcp;
struct segment_command sg = *sgp;
if(swap_load_commands)
swap_segment_command(&sg, host_byte_sex);
if(filetype == MH_OBJECT)
{
align = MINSEGALIGN32;
struct section *sp = (struct section *)((char *)sgp +
sizeof(struct segment_command));
for(uint32_t j = 0; j < sg.nsects; ++j)
{
struct section s = *sp;
if(swap_load_commands)
swap_section(&s, 1, host_byte_sex);
if(s.align > align)
align = s.align;
sp++;
}
}
else
{
align = guess_align(sg.vmaddr, MINSEGALIGN32, MAXSEGALIGN);
}
}
else if(l.cmd == LC_SEGMENT_64)
{
struct segment_command_64* sgp = (struct segment_command_64 *)lcp;
struct segment_command_64 sg = *sgp;
if(swap_load_commands)
swap_segment_command_64(&sg, host_byte_sex);
if(mhp64->filetype == MH_OBJECT)
{
align = MINSEGALIGN64;
struct section_64 *sp = (struct section_64 *)((char *)sgp +
sizeof(struct segment_command_64));
for(uint32_t j = 0; j < sg.nsects; ++j)
{
struct section_64 s = *sp;
if(swap_load_commands)
swap_section_64(&s, 1, host_byte_sex);
if(s.align > align)
align = s.align;
sp++;
}
}
else
{
align = guess_align(sg.vmaddr, MINSEGALIGN64, MAXSEGALIGN);
}
}
if(align < cur_align)
cur_align = align;
lcp = (struct load_command *)((char *)lcp + l.cmdsize);
}
return cur_align;
}