It is really confused me a lot! When I read apple open source code of getsecbyname.c. Some code In it:
uint8_t *
getsectiondata(
const struct mach_header *mhp,
const char *segname,
const char *sectname,
unsigned long *size) {
slide = 0;
sp = 0;
sgp = (struct segment_command *)
((char *)mhp + sizeof(struct mach_header));
for(i = 0; i < mhp->ncmds; i++){
if(sgp->cmd == LC_SEGMENT){
if(strcmp(sgp->segname, "__TEXT") == 0){
slide = (uintptr_t)mhp - sgp->vmaddr;
}
......
}
I can understand what is ASLR(Address Space Layout Random). And I also know that slide's value should be equal to loader address subtract linker address: slide = L(loader address) - A(linker address). But why slide value in here which is slide = (uintptr_t)mhp - sgp->vmaddr;. Does that mean mhp(mach_header) is the loader address? I can constrainedly recognize "__TEXT"'s vmaddr is the linker address because which is read from the load command. But why the mach_header address become the loader address in here, which should be always 0x00000000 in my opinion.
And I have roughly read the source code of xnu of Apple. I read function load_machfile and function parse_machfile consisted in xnu source earnestly. However, I'm more confused now. I really appreciate if someone can help me!
By necessity, the Mach-O header is at file offset 0 (otherwise it wouldn't be a header). And by convention, the __TEXT segment maps the content at file offset 0. So the address of the Mach-O header and that of the __TEXT segment are one and the same.
Now you just have to get the link-time value and the runtime value of that address, subtract one from the other and you have the slide. The value in
sgp->vmaddris the link-time one, because the Mach-O header is not modified during load (and it will usually be0x100000000for standalone executables if you didn't pass any custom linker options). Meanwhile,mhpis a live pointer so it is the same value, but with the slide applied.