Search logs:

channel logs for 2004 - 2010 are archived at ·· can't be searched

#osdev2 = #osdev @ Libera from 23may2021 to present

#osdev @ OPN/FreeNode from 3apr2001 to 23may2021

all other channels are on OPN/FreeNode from 2004 to present

Friday, 21 January 2022

12:20:00 <junon> Is RIP-Relative mode what is used with you compile with PIE?
12:22:00 <junon> err, rip-relative addressing*, not mode
12:23:00 <klange> Should be. RIP-relative was a big improvement over the thunks that were used in 32-bit x86.
12:24:00 <junon> I thought x86 already had EIP-relative addressing though? e.g. jmp short and whatnot. Am I misremembering?
12:24:00 <zid> that's not an addressing mode
12:26:00 <junon> What does addressing mode mean here, then? Just for reads/writes?
12:27:00 <Mutabah> yes.
12:27:00 <Mutabah> For doing memory accesses
12:28:00 <klange> You want to load a library somewhere [or for PIE, an executable image]. You _could_ load it and then rewrite all the data references, but now you've trashed all of the code with writes and your bovines are now sad.
12:30:00 <klange> Instead you use RIP-relative addressing. Your static data gets loaded with the code as a single segment (or two... r/w/x separation...) and the code knows where it is relative to itself and that doesn't change when you stick the lot at different addresess
12:31:00 <klange> now all that code can remain cow-friendly, and because it's not doing extra function calls to extract EIP from stack frames, it's not any slower for it
12:34:00 <froggey> mooo
12:40:00 <junon> ahhhhhh
12:40:00 <junon> for static data, right
12:41:00 <junon> neat.
12:41:00 <junon> thanks klange
12:42:00 <zid> lea rsi, [dll_base_addr]
12:43:00 <zid> add rsi, symbol_offset
12:43:00 <zid> mov eax, [rsi]
12:43:00 <zid> vs. mov rsi, [rip+0x8394]
12:43:00 <zid> well not dll, .o
12:45:00 <junon> Oh okay I have definitely seen that.
12:45:00 <junon> in some disasm output before
12:46:00 <junon> also TIL NOP is actually XCHG EAX, EAX under the hood, and that AMD64 keeps it that way regardless of size prefixes.
12:46:00 <junon> Why would that make a difference, though? Why not... do nothing? Is there an observable side effect to XCHG EAX,EAX that had to be preserved?
12:47:00 <zid> it actually doesn't do that
12:47:00 <zid> because it'd break a whole bunch of programs
12:47:00 <junon> Ohhh it doesn't do that? The writing is vague
12:48:00 <junon> section 2.5.7: > Without special handling in 64-bit mode, the instruction would not be a true no-operation. Therefore, in 64-bit mode the processor treats opcode 90h (the legacy XCHG EAX, EAX instruction) as a true NOP, regardless of a REX operand-size prefix.
12:48:00 <zid> that's precisely what it says
12:48:00 <zid> it says it DOES NOT do it, because that would *not* be a nop
12:48:00 <zid> so it *has* to replace it with nop, because otherwise it'd.. clear the upper bits of rax
12:49:00 <junon> Riiiiight okay.
12:49:00 <junon> is that because 90h is an encoded instruction?
12:49:00 <junon> there was no dedicated, true NOP?
12:50:00 <zid> 90 is nop
12:50:00 <zid> and happens to be where xchg eax, eax *would* be
12:50:00 <zid> if you looked at a little map
12:51:00 <junon> Gotcha, so it was effectively NOP in x86 but because of zero extension in 64-bit mode it has side effects if treated as such, so AMD64 has special handling
12:51:00 <junon> is what I'm understanding
12:51:00 <zid> idk the exact encoding but you could imagine 7E: xchg rbx, rdx 7F: xchg rbx, rcx 80: nop 81: xchg rax, rdi 82: ..
12:51:00 <junon> or, maybe not zero extension but truncation
12:51:00 <zid> it just takes the place of xchg rax, rax
12:51:00 <junon> right
12:51:00 <junon> okay
12:52:00 <zid> it's just letting you know not to assume it does xchg rax, rax and people *treat* that as a nop
12:52:00 <zid> it actually *is* a nop
12:52:00 <junon> Cool, makes sense. Thanks zid :)
20:11:00 <geist> huh TIL that 90 is xchg
20:11:00 <geist> didn't know that
20:13:00 <geist> also to take it to the next level there are lots of ways to encode nops on x86. 90 is the 1 byte, but some of the optimization and/or programming manuals for intel and amd give you a list of suggested nops from 1 - 15 bytes
20:13:00 <geist> for padding purposes if you need say a 3 byte nop use this, or 6 byte, etc
20:13:00 <geist> usually it's a raw nop + some prefixes and such
20:14:00 <GeDaMo>
20:14:00 <bslsk05> ​ assembly - Long multi-byte NOPs: commonly understood macros or other notation - Stack Overflow
20:15:00 * gog nop-sleds into the room
20:15:00 <geist> yah.
20:15:00 * geist pets gog
20:16:00 * gog purrs
20:16:00 <geist> i wonder what the raw encoding of the 0f prefixed nop is?
20:17:00 <zid> nop dword ptr [eax]
20:17:00 <zid> I really like that just in general
20:17:00 <geist> hmmm, according to sandpile its simply nop, yeah
20:18:00 <geist> 0x0f group which is a standard 2 byte opcode group
20:18:00 <zid> some of them are leas with the same src and dst reg
20:18:00 <zid> lea rsi, [rsi*1+0]
20:18:00 <zid> but I don't think anything uses those ones they all just stack nops
20:19:00 <zid> nop dword [eax+0] nop dword[eax+eax*1+0] nop dword [eax + 0x00000000] ...
20:19:00 <geist> then 0x1f which is 'group 16' in sandpile
20:19:00 <geist> i dont get where it consumes the next byte byte there ya go
20:19:00 <zid> 0f is all the cool kid opcodes
20:20:00 <geist> the next byte (0 for 3 byte ones) is probably mod/rm or something
20:20:00 <geist> and thus you get multiple sizes of that
20:20:00 <geist> according to sandpile it was added in p6
20:21:00 <geist> oh and that stackoverflow lists the pre p6 versions, which seem to be leas, yeah