flat assembler
Message board for the users of flat assembler.
Index
> Main > Alignment and padding Goto page 1, 2 Next |
Author |
|
Furs 30 Apr 2017, 20:01
I agree, btw it's one of the complaints I had with GNU GAS (i.e. basically stuff compiled with GCC) but as usual they don't give a shit of good suggestions, which is one of the reasons I dislike the FSF because of their attitude. Yes, GCC/GAS pads with nops non-accessible sections of code, sometimes multi-byte nops. That's retarded.
Though, any unprivileged 1-byte instruction does the job (hlt comes to mind) not just int3. |
|||
30 Apr 2017, 20:01 |
|
system error 01 May 2017, 00:35
VEG wrote:
0xCC is actually not used for paddings. It's microsoft's own security thingies. (security patches, security certificates etc), most probably to prevent buffer overrun among other evil things. On the contrary, 0xCC means do something, like invoking a debugger. NOP simply means do nothing. If you're using PowerPoint for presentation before the world audience, you don't want a 0xCC to 'interrupt' your presentations by invoking CPU's internal porn if something went wrong. It's ugly and disastrous from HCI standpoint. |
|||
01 May 2017, 00:35 |
|
revolution 01 May 2017, 00:41
system error wrote: If you're using PowerPoint for presentation before the world audience, you don't want a 0xCC to 'interrupt' your presentations ... I think I'd rather have int3 being executed and crashing the program. At least then I'd immediately know it is faulty and where is faulted. The alternative with nops is potentially a much harder problem to discover and fix. |
|||
01 May 2017, 00:41 |
|
system error 01 May 2017, 00:51
revolution wrote:
Both crashes / freezes the same way anyway. But that extra 'capability' of int3 to invoke something else is the reason why it should not be used for user application paddings, let alone alignment padding. NOP is lightweight. int3 is an overkill for purposes other than debugging and developing. Btw, in many areas, Windows do use NOPs for padding purposes but use 0xCC where security measures are needed to immediately redirect suspicious codes to the internal debugger. |
|||
01 May 2017, 00:51 |
|
revolution 01 May 2017, 00:58
Code: ;... proc animate_rainbows_and_unicorns ... push ebp ;exciting animation code goes here pop ebp ;we're done endp ;oops forgot the ret nop ;alignment proc delete_all_user_data_and_DBs ... push ebp ;deletion code goes here ;... |
|||
01 May 2017, 00:58 |
|
system error 01 May 2017, 01:08
revolution wrote:
I don't think so. int3 is never a solution and never design to be a solution to programmers own mistakes in their final products. We have flowcharts, pseudocodes, ERD diagrams etc for that. You don't sell 'debuggish' products to end-users. Similarly in ARM/Android, I don't want to see the content of the registers once the CandyCrush crashed, let alone 10 year olds and grannies! |
|||
01 May 2017, 01:08 |
|
system error 01 May 2017, 01:26
Here's some light reading on how Windows uses 0xCC as a security measure - not exactly for general padding 'solution'.
http://www.ksyash.com/2011/01/buffer-overflow-protection-3/ |
|||
01 May 2017, 01:26 |
|
VEG 01 May 2017, 04:58
Quote: Both crashes / freezes the same way anyway. Quote: But that extra 'capability' of int3 to invoke something else is the reason why it should not be used for user application paddings Quote: NOP is lightweight. Quote: 0xCC is actually not used for paddings. It's microsoft's own security thingies. IMHO, three types of paddings are good in different situations: — nop (0x90 and 2+ bytes variants) is good for padding things inside a procedure, just because it is intended to be executed. — 0xCC is good for padding between procedures, just because this code isn't intended to be executed — 0x00 for padding in data sections. |
|||
01 May 2017, 04:58 |
|
revolution 01 May 2017, 05:45
- 0xFF for padding in FLASH & EEPROM memories.
|
|||
01 May 2017, 05:45 |
|
revolution 01 May 2017, 05:58
system error wrote: I don't think so. int3 is never a solution and never design to be a solution to programmers own mistakes in their final products. We have flowcharts, pseudocodes, ERD diagrams etc for that. You don't sell 'debuggish' products to end-users. Similarly in ARM/Android, I don't want to see the content of the registers once the CandyCrush crashed, let alone 10 year olds and grannies! I can't agree that in my code above that nop is a better choice. I also can't agree about measuring the weight (lightweight solution?) of an instruction that isn't supposed to be executed. There is the recommendation in the AMD manual that suggests to use int3 for padding to tell the prefetcher & decoder to stop wasting power and resources and do something else. |
|||
01 May 2017, 05:58 |
|
zhak 01 May 2017, 09:22
Why aligning with zeros is not considered? Paddings are not intended to be executed. If padded area is executed, it is an error and will lead to a crash sooner or later. So why not just align with zeros both code and data?
|
|||
01 May 2017, 09:22 |
|
Furs 01 May 2017, 10:38
zhak wrote: Why aligning with zeros is not considered? Paddings are not intended to be executed. If padded area is executed, it is an error and will lead to a crash sooner or later. So why not just align with zeros both code and data? Zero pad could lead to patterns being recognized as completely different instructions. Maybe unlikely, but still possible, so why do it when it offers zero advantages to int3? system error wrote: I don't think so. int3 is never a solution and never design to be a solution to programmers own mistakes in their final products. We have flowcharts, pseudocodes, ERD diagrams etc for that. You don't sell 'debuggish' products to end-users. Similarly in ARM/Android, I don't want to see the content of the registers once the CandyCrush crashed, let alone 10 year olds and grannies! Even a grandma can copy paste and submit a crash dump if she wants to. Also: "security" exploits happen because of badly written code. Perfectly written code has no exploits. Furthermore, 0xCC can help with more than just "exploits" and "badly written code". Suppose there's a fault in the CPU, or a bit flip in the CPU cache's itself due to quantum effects or cosmic rays or whatever else you can't control, and somehow it changed the instruction pointer's bit so it now points to padding. (perhaps it changed the return address on the stack) Would you rather have the application crash so there's no room for disaster or let it continue and silently ruin the rest of your data? (because you have no idea such a flip even happened). Note that it is unlikely it won't also crash with nops, because it will most likely (99.9999%) crash also with nops, so what's the difference in this case? Except making it harder to track down (because it will crash at a completely innocent-looking instruction, due to messed up stack or whatever). Even so, revolution's example demonstrates what can happen if it will NOT crash (the 0.0001% or whatever); it could even delete the entire database. Extremely unlikely, but still a chance higher than zero, and the alternative (crash) is absolutely not any better than 0xCC, so what's the point?!? It's unlikely but still higher than zero chance -- and there's no disadvantage to do it, so why not? The application should rather crash than continue executing with the wrong instructions. The same reason your PC will automatically crash by design if an ECC error is detected in RAM: you seriously do not want to continue with corrupted memory which can do unspeakable things. Of course with ECC RAM you will need two bit flips (highly unlikely) for it to crash by design, since it can automatically correct 1 bit errors. That's not the reason I use ECC RAM though. Double bit flips are incredibly rare, but non-ECC RAM cannot detect them as far as I know. That leads to silent corruption of data. Silent because your computer won't crash (just as you want) and you'll have no idea it even happened, until you save the file, back it up, then years later try to reload it and find out it's fucked up. Backup won't do you any good if the file's data itself is messed up before it is even written to the backup. |
|||
01 May 2017, 10:38 |
|
system error 02 May 2017, 02:29
VEG wrote: Not always. Sometimes it can execute some code which will not cause a crash directly. I had such situation. 0xCC as a filler could help. That's exactly what I meant by 'possibility'. No further work needed for NOP. Quote: 0x90 as lightweight as 0xCC. Just one byte in both situations. 0xCC is not a lightweight instruction. Don't be fooled by '1' byte convenience. It involves myriads of microcodes and CPU resources. You can't compare that with 'do nothing' 1-byte NOP. I don't understand how you defined lightweight vs heavyweight. Quote: You're not right. 0xCC often is used for paddings. As I had mentioned it before, LLVM uses 0xCC for paddings in x86 programs. LLVM is used for compiling C++ or Rust programs, as well as many other different languages. It seems that Microsoft Visual C++ also uses 0xCC for paddings between procedures: It is not padding in general sense. Padding is applied at compile time. int3 is a security measure and counter-measure which is activated at runtime like for example providing guard bytes for local variables (means stack that grows and shrinks dynamically). Also for security cookies. Do you write your own security cookies for your programs? Nope. Because it's generated at runtime. It's not convenient if not practically impossible. Maybe we can ask Tomasz Gryzstar to provide PROC and INVOKE macros that has 0xCC at each ends and at every locals? How convenient could that be? int3 is a high-level language thing which is implemented with full support from the OS, like VC++ or else you'll have to write your own interrupt handlers for every different part of your codes. |
|||
02 May 2017, 02:29 |
|
system error 02 May 2017, 02:41
revolution wrote:
Catching exceptions should be done by the O.S and by the internal code even more conveniently and safely than to let the debugger catch it and blow things up in your face. Try Java that runs 'billions of devices' without having to expose it's own internal bytecodes everytime they screwed up half-way. The principle is simple: let software faults be handled by software exception handlers. Using 0xCC to trigger some hardware reactions might not be safe anyway if compared to plain 0x90. |
|||
02 May 2017, 02:41 |
|
system error 02 May 2017, 02:56
Quote: -- snipped -- If ECC error occurs, then it's called malfunction PC or mobo. Hahaha. It has nothing to do with 0x90. Even 0xCC won't work by that time. Also don't forget the facts that a mishandled hardware interrupt can ruin your entire harddisk too! Just so you know that int3 is just a 'protected' int 13h. They are from the same interrupt family by the way |
|||
02 May 2017, 02:56 |
|
Furs 02 May 2017, 12:17
ECC has nothing to do with 0x90, no, but read the context again. The context was about problems out of your control. You know, random bit flips can happen, right? Go look it up on revolution's website. It's batshit crazy in my opinion to not use ECC memory these days because of the densities of RAM cells are so high (thus easily flipped). Even the damn GPU RAM uses ECC. It's not always faulty hardware. ECC protects against random bit flips. Cosmic ray radiation exists (in a plane there's a higher chance of a bit flip since you're not as protected as at sea level by the Earth) and other factors (such as quantum tunneling) which can randomly flip a bit.
However, let's go back to the point. How do you think exceptions get generated? int3 triggers an exception, so does hlt or other unprivileged instruction. nop doesn't, and that's the problem. Do you understand how stupidly unsafe it is to run an arbitrary function? The return address of the function is pushed on the stack, but if you run a random function (because of nops) instead of triggering an exception, it will "return" to whatever was on top of the stack before. This return can be any arbitrary code (to delete your data), but it most likely will just crash because it will be an invalid page, or it will point to data instead of code, or whatever. So there's 2 cases: Case 1: nop crashes just as 0xCC does with an exception -- except it makes tracking it down way harder, so why use it? Case 2: nop doesn't crash but does something horrible executing random code (perhaps an attacker already exploited it!) Tell me in which case does nop even hold an advantage? If anything it's a hazard because of case 2, and an annoyance because of case 1 (hard to track down, it will crash at a random/innocent instruction due to bad stack etc). But it seems you think int3 automatically runs the debugger and it has magical powers instead of just triggering an exception (that can be identified by the debugger of course). So use another unprivileged instruction then, like hlt. hlt will trigger an exception since it's not a useable instruction from usercode so you can let Windows do its magical thing you think it does. (it's also 1 byte long so it's safe) No excuse to use nop. |
|||
02 May 2017, 12:17 |
|
system error 03 May 2017, 23:30
Furs wrote: No excuse to use nop. Code: IF PE = 0 THEN GOTO REAL-ADDRESS-MODE; ELSE (* PE = 1 *) IF (VM = 1 and IOPL < 3 AND INT n) THEN #GP(0); (* Bit 0 of error code is 0 because INT n *) ELSE (* Protected mode, IA-32e mode, or virtual-8086 mode interrupt *) IF (IA32_EFER.LMA = 0) THEN (* Protected mode, or virtual-8086 mode interrupt *) GOTO PROTECTED-MODE; ELSE (* IA-32e mode interrupt *) GOTO IA-32e-MODE; FI; FI; FI; REAL-ADDRESS-MODE: IF ((vector_number « 2) + 3) is not within IDT limit THEN #GP; FI; IF stack not large enough for a 6-byte return information THEN #SS; FI; Push (EFLAGS[15:0]); IF ← 0; (* Clear interrupt flag *) TF ← 0; (* Clear trap flag *) AC ← 0; (* Clear AC flag *) Push(CS); Push(IP); (* No error codes are pushed in real-address mode*) CS ← IDT(Descriptor (vector_number « 2), selector)); EIP ← IDT(Descriptor (vector_number « 2), offset)); (* 16 bit offset AND 0000FFFFH *) END; PROTECTED-MODE: IF ((vector_number « 3) + 7) is not within IDT limits or selected IDT descriptor is not an interrupt-, trap-, or task-gate type THEN #GP(error_code(vector_number,1,EXT)); FI; (* idt operand to error_code set because vector is used *) IF software interrupt (* Generated by INT n, INT3, or INTO *) THEN IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *) THEN #GP(error_code(vector_number,1,0)); FI; (* idt operand to error_code set because vector is used *) (* ext operand to error_code is 0 because INT n, INT3, or INTO*) FI; IF gate not present THEN #NP(error_code(vector_number,1,EXT)); FI; (* idt operand to error_code set because vector is used *) IF task gate (* Specified in the selected interrupt table descriptor *) THEN GOTO TASK-GATE; ELSE GOTO TRAP-OR-INTERRUPT-GATE; (* PE = 1, trap/interrupt gate *) FI; END; IA-32e-MODE: IF INTO and CS.L = 1 (64-bit mode) THEN #UD; FI; IF ((vector_number « 4) + 15) is not in IDT limits or selected IDT descriptor is not an interrupt-, or trap-gate type THEN #GP(error_code(vector_number,1,EXT)); (* idt operand to error_code set because vector is used *) FI; IF software interrupt (* Generated by INT n, INT 3, or INTO *) THEN IF gate DPL < CPL (* PE = 1, DPL < CPL, software interrupt *) THEN #GP(error_code(vector_number,1,0)); (* idt operand to error_code set because vector is used *) (* ext operand to error_code is 0 because INT n, INT3, or INTO*) FI; FI; IF gate not present THEN #NP(error_code(vector_number,1,EXT)); (* idt operand to error_code set because vector is used *) FI; GOTO TRAP-OR-INTERRUPT-GATE; (* Trap/interrupt gate *) END; TASK-GATE: (* PE = 1, task gate *) Read TSS selector in task gate (IDT descriptor); IF local/global bit is set to local or index not within GDT limits THEN #GP(error_code(TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) Access TSS descriptor in GDT; IF TSS descriptor specifies that the TSS is busy (low-order 5 bits set to 00001) THEN #GP(TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) IF TSS not present THEN #NP(TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) SWITCH-TASKS (with nesting) to TSS; IF interrupt caused by fault with error code THEN IF stack limit does not allow push of error code THEN #SS(EXT); FI; Push(error code); FI; IF EIP not within code segment limit THEN #GP(EXT); FI; END; TRAP-OR-INTERRUPT-GATE: Read new code-segment selector for trap or interrupt gate (IDT descriptor); IF new code-segment selector is NULL THEN #GP(EXT); FI; (* Error code contains NULL selector *) IF new code-segment selector is not within its descriptor table limits THEN #GP(error_code(new code-segment selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) Read descriptor referenced by new code-segment selector; IF descriptor does not indicate a code segment or new code-segment DPL > CPL THEN #GP(error_code(new code-segment selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) IF new code-segment descriptor is not present, THEN #NP(error_code(new code-segment selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) IF new code segment is non-conforming with DPL < CPL THEN IF VM = 0 THEN GOTO INTER-PRIVILEGE-LEVEL-INTERRUPT; (* PE = 1, VM = 0, interrupt or trap gate, nonconforming code segment, DPL < CPL *) ELSE (* VM = 1 *) IF new code-segment DPL ≠ 0 THEN #GP(error_code(new code-segment selector,0,EXT)); (* idt operand to error_code is 0 because selector is used *) GOTO INTERRUPT-FROM-VIRTUAL-8086-MODE; FI; (* PE = 1, interrupt or trap gate, DPL < CPL, VM = 1 *) FI; ELSE (* PE = 1, interrupt or trap gate, DPL ≥ CPL *) IF VM = 1 THEN #GP(error_code(new code-segment selector,0,EXT)); (* idt operand to error_code is 0 because selector is used *) IF new code segment is conforming or new code-segment DPL = CPL THEN GOTO INTRA-PRIVILEGE-LEVEL-INTERRUPT; ELSE (* PE = 1, interrupt or trap gate, nonconforming code segment, DPL > CPL *) #GP(error_code(new code-segment selector,0,EXT)); (* idt operand to error_code is 0 because selector is used *) FI; FI; END; INTER-PRIVILEGE-LEVEL-INTERRUPT: (* PE = 1, interrupt or trap gate, non-conforming code segment, DPL < CPL *) IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) THEN (* Identify stack-segment selector for new privilege level in current TSS *) IF current TSS is 32-bit THEN TSSstackAddress ← (new code-segment DPL « 3) + 4; IF (TSSstackAddress + 5) > current TSS limit THEN #TS(error_code(current TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) NewSS ← 2 bytes loaded from (TSS base + TSSstackAddress + 4); NewESP ← 4 bytes loaded from (TSS base + TSSstackAddress); ELSE (* current TSS is 16-bit *) TSSstackAddress ← (new code-segment DPL « 2) + 2 IF (TSSstackAddress + 3) > current TSS limit THEN #TS(error_code(current TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) NewSS ← 2 bytes loaded from (TSS base + TSSstackAddress + 2); NewESP ← 2 bytes loaded from (TSS base + TSSstackAddress); FI; IF NewSS is NULL THEN #TS(EXT); FI; IF NewSS index is not within its descriptor-table limits or NewSS RPL ≠ new code-segment DPL THEN #TS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) Read new stack-segment descriptor for NewSS in GDT or LDT; IF new stack-segment DPL ≠ new code-segment DPL or new stack-segment Type does not indicate writable data segment THEN #TS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) IF NewSS is not present THEN #SS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) ELSE (* IA-32e mode *) IF IDT-gate IST = 0 THEN TSSstackAddress ← (new code-segment DPL « 3) + 4; ELSE TSSstackAddress ← (IDT gate IST « 3) + 28; FI; IF (TSSstackAddress + 7) > current TSS limit THEN #TS(error_code(current TSS selector,0,EXT); FI; (* idt operand to error_code is 0 because selector is used *) NewRSP ← 8 bytes loaded from (current TSS base + TSSstackAddress); NewSS ← new code-segment DPL; (* NULL selector with RPL = new CPL *) FI; IF IDT gate is 32-bit THEN IF new stack does not have room for 24 bytes (error code pushed) or 20 bytes (no error code pushed) THEN #SS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) FI ELSE IF IDT gate is 16-bit THEN IF new stack does not have room for 12 bytes (error code pushed) or 10 bytes (no error code pushed); THEN #SS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) ELSE (* 64-bit IDT gate*) IF StackAddress is non-canonical THEN #SS(EXT); FI; (* Error code contains NULL selector *) FI; FI; IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) THEN IF instruction pointer from IDT gate is not within new code-segment limits THEN #GP(EXT); FI; (* Error code contains NULL selector *) ESP ← NewESP; SS ← NewSS; (* Segment descriptor information also loaded *) ELSE (* IA-32e mode *) IF instruction pointer from IDT gate contains a non-canonical address THEN #GP(EXT); FI; (* Error code contains NULL selector *) RSP ← NewRSP & FFFFFFFFFFFFFFF0H; SS ← NewSS; FI; IF IDT gate is 32-bit THEN CS:EIP ← Gate(CS:EIP); (* Segment descriptor information also loaded *) ELSE IF IDT gate 16-bit THEN CS:IP ← Gate(CS:IP); (* Segment descriptor information also loaded *) ELSE (* 64-bit IDT gate *) CS:RIP ← Gate(CS:RIP); (* Segment descriptor information also loaded *) FI; FI; IF IDT gate is 32-bit THEN Push(far pointer to old stack); (* Old SS and ESP, 3 words padded to 4 *) Push(EFLAGS); Push(far pointer to return instruction); (* Old CS and EIP, 3 words padded to 4 *) Push(ErrorCode); (* If needed, 4 bytes *) ELSE IF IDT gate 16-bit THEN Push(far pointer to old stack); (* Old SS and SP, 2 words *) Push(EFLAGS(15-0]); Push(far pointer to return instruction); (* Old CS and IP, 2 words *) Push(ErrorCode); (* If needed, 2 bytes *) ELSE (* 64-bit IDT gate *) Push(far pointer to old stack); (* Old SS and SP, each an 8-byte push *) Push(RFLAGS); (* 8-byte push *) Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *) Push(ErrorCode); (* If needed, 8-bytes *) FI; FI; CPL ← new code-segment DPL; CS(RPL) ← CPL; IF IDT gate is interrupt gate THEN IF ← 0 (* Interrupt flag set to 0, interrupts disabled *); FI; TF ← 0; VM ← 0; RF ← 0; NT ← 0; END; INTERRUPT-FROM-VIRTUAL-8086-MODE: (* Identify stack-segment selector for privilege level 0 in current TSS *) IF current TSS is 32-bit THEN IF TSS limit < 9 THEN #TS(error_code(current TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) NewSS ← 2 bytes loaded from (current TSS base + 8); NewESP ← 4 bytes loaded from (current TSS base + 4); ELSE (* current TSS is 16-bit *) IF TSS limit < 5 THEN #TS(error_code(current TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) NewSS ← 2 bytes loaded from (current TSS base + 4); NewESP ← 2 bytes loaded from (current TSS base + 2); FI; IF NewSS is NULL THEN #TS(EXT); FI; (* Error code contains NULL selector *) IF NewSS index is not within its descriptor table limits or NewSS RPL ≠ 0 THEN #TS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) Read new stack-segment descriptor for NewSS in GDT or LDT; IF new stack-segment DPL ≠ 0 or stack segment does not indicate writable data segment THEN #TS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) IF new stack segment not present THEN #SS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) IF IDT gate is 32-bit THEN IF new stack does not have room for 40 bytes (error code pushed) or 36 bytes (no error code pushed) THEN #SS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) ELSE (* IDT gate is 16-bit) IF new stack does not have room for 20 bytes (error code pushed) or 18 bytes (no error code pushed) THEN #SS(error_code(NewSS,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) FI; IF instruction pointer from IDT gate is not within new code-segment limits THEN #GP(EXT); FI; (* Error code contains NULL selector *) tempEFLAGS ← EFLAGS; VM ← 0; TF ← 0; RF ← 0; NT ← 0; IF service through interrupt gate THEN IF = 0; FI; TempSS ← SS; TempESP ← ESP; SS ← NewSS; ESP ← NewESP; (* Following pushes are 16 bits for 16-bit IDT gates and 32 bits for 32-bit IDT gates; Segment selector pushes in 32-bit mode are padded to two words *) Push(GS); Push(FS); Push(DS); Push(ES); Push(TempSS); Push(TempESP); Push(TempEFlags); Push(CS); Push(EIP); GS ← 0; (* Segment registers made NULL, invalid for use in protected mode *) FS ← 0; DS ← 0; ES ← 0; CS:IP ← Gate(CS); (* Segment descriptor information also loaded *) IF OperandSize = 32 THEN EIP ← Gate(instruction pointer); ELSE (* OperandSize is 16 *) EIP ← Gate(instruction pointer) AND 0000FFFFH; FI; (* Start execution of new routine in Protected Mode *) END; INTRA-PRIVILEGE-LEVEL-INTERRUPT: (* PE = 1, DPL = CPL or conforming segment *) IF IA32_EFER.LMA = 1 (* IA-32e mode *) IF IDT-descriptor IST ≠ 0 THEN TSSstackAddress ← (IDT-descriptor IST « 3) + 28; IF (TSSstackAddress + 7) > TSS limit THEN #TS(error_code(current TSS selector,0,EXT)); FI; (* idt operand to error_code is 0 because selector is used *) NewRSP ← 8 bytes loaded from (current TSS base + TSSstackAddress); FI; IF 32-bit gate (* implies IA32_EFER.LMA = 0 *) THEN IF current stack does not have room for 16 bytes (error code pushed) or 12 bytes (no error code pushed) THEN #SS(EXT); FI; (* Error code contains NULL selector *) ELSE IF 16-bit gate (* implies IA32_EFER.LMA = 0 *) IF current stack does not have room for 8 bytes (error code pushed) or 6 bytes (no error code pushed) THEN #SS(EXT); FI; (* Error code contains NULL selector *) ELSE (* IA32_EFER.LMA = 1, 64-bit gate*) IF NewRSP contains a non-canonical address THEN #SS(EXT); (* Error code contains NULL selector *) FI; FI; IF (IA32_EFER.LMA = 0) (* Not IA-32e mode *) THEN IF instruction pointer from IDT gate is not within new code-segment limit THEN #GP(EXT); FI; (* Error code contains NULL selector *) ELSE IF instruction pointer from IDT gate contains a non-canonical address THEN #GP(EXT); FI; (* Error code contains NULL selector *) RSP ← NewRSP & FFFFFFFFFFFFFFF0H; FI; IF IDT gate is 32-bit (* implies IA32_EFER.LMA = 0 *) THEN Push (EFLAGS); Push (far pointer to return instruction); (* 3 words padded to 4 *) CS:EIP ← Gate(CS:EIP); (* Segment descriptor information also loaded *) Push (ErrorCode); (* If any *) ELSE IF IDT gate is 16-bit (* implies IA32_EFER.LMA = 0 *) THEN Push (FLAGS); Push (far pointer to return location); (* 2 words *) CS:IP ← Gate(CS:IP); (* Segment descriptor information also loaded *) Push (ErrorCode); (* If any *) ELSE (* IA32_EFER.LMA = 1, 64-bit gate*) Push(far pointer to old stack); (* Old SS and SP, each an 8-byte push *) Push(RFLAGS); (* 8-byte push *) Push(far pointer to return instruction); (* Old CS and RIP, each an 8-byte push *) Push(ErrorCode); (* If needed, 8 bytes *) CS:RIP ← GATE(CS:RIP); (* Segment descriptor information also loaded *) FI; FI; CS(RPL) ← CPL; IF IDT gate is interrupt gate THEN IF ← 0; FI; (* Interrupt flag set to 0; interrupts disabled *) TF ← 0; NT ← 0; VM ← 0; RF ← 0; END; Which part of overkill that you didn't understand? Show me your int3 interrupt handlers that you've written so far for your polished programs / library. |
|||
03 May 2017, 23:30 |
|
revolution 04 May 2017, 00:19
system error wrote: ... invoking Trap Gate, Task Gate, setting up IVT, entering etc etc? |
|||
04 May 2017, 00:19 |
|
system error 04 May 2017, 04:06
revolution wrote: I'd still much rather have that than other unknown random actions happening. Maybe that's why we have software interrupt or software exception handlers. I've given you Java example. One faulty move, other process can still run. With improper int3 handling, you can't even move a muscle because it takes control of your hardware state. I mean, do I have to teach you this basic thing? Just because Windows has its own internal debugger (which is a SOFTWARE INTERRUPT HANDLER anyway), you should not be fooled into believing that 0xCC can be handled like a breeze because it is not. What Windows does is to hide the implementation details of int3 (by using its own internal debugger for the users) so that they 'feel' comfortable working with 0xCC in and around their apps. Without such convenience, I believe people won't be tough talk on using 0xCC. |
|||
04 May 2017, 04:06 |
|
Goto page 1, 2 Next < Last Thread | Next Thread > |
Forum Rules:
|
Copyright © 1999-2025, Tomasz Grysztar. Also on GitHub, YouTube.
Website powered by rwasa.