Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I use interrupts to trigger a divide-by-zero error exception in x86 assembly?

Tags:

linux

assembly

I am trying to understand interrupts in x86 assembly.

I tried to trigger a divide-by-zero error, which corresponds to code 0.

int $0

I was expecting this to have the same behavior as dividing by zero.

movl $0, %edx # dividend
movl $0, %eax # dividend
movl $0, %edi # divisor
divl %edi

In the former case, my program crashes with a "Segmentation fault" and exit code 139 on Linux. In the latter case, my program crashes with a "Floating point exception" and exit code 136 on Linux.

How can I use an interrupt to trigger the same error as calling the div instruction with a zero divisor?

like image 977
dannyadam Avatar asked Oct 15 '17 14:10

dannyadam


People also ask

Which interrupt get generated when divide by zero error occur?

The operating system sets up the functions (interrupt handler, exception handler) for each event. When a divide by zero occurs, it triggers an exception. The CPU responds by invoking the exception handler in the interrupt vector corresponding to a divide by zero.

Which system interrupt is used for system calls in Xv6?

Xv6 maps the 32 hardware inter- rupts to the range 32-63 and uses interrupt 64 as the system call interrupt.

What is an assembly interrupt?

An interrupt is actually a call to a subroutine, but initiated by the peripheral hardware itself and not by the "CALL" instruction. The interrupt is asynchronous and can occur at any time during the execution of the main program.

Which interrupt is invoked when an invalid instruction is encountered by a CPU?

Aborts are used to report severe errors, such as hardware failures and invalid or inconsistent values in system tables. The interrupt signal sent by the control unit is an emergency signal used to switch control to the corresponding abort exception handler.


1 Answers

I was expecting this to have the same behavior as dividing by zero.

In principle this is correct.

I tried to trigger a divide-by-zero error, which corresponds to code 0.

int $0

In principle this is still correct.

In the former case, my program crashes with a "Segmentation fault" and exit code 139 on Linux. In the latter case, my program crashes with a "Floating point exception" and exit code 136 on Linux.

x86 CPUs have two operating modes: Real Mode and Protected Mode (64-bit CPUs have a third mode: Long Mode)

In Real Mode you can execute any instruction the CPU is supporting in Real Mode. However Real Mode normally only allows 16-bit code and addressing up to 1 MB of memory. 32-bit operating systems run in Protected Mode.

In Protected Mode two special bits in the cs register indicate if the code currently running belongs to the operating system kernel or to an application.

In Protected Mode ...

  • ... some instructions (e.g. lmsw) can only be called by the operating system
  • ... some instructions (e.g. cli) can only be called by applications if the operating system sets some special bits in some register; otherwise only the operating system can call these instructions
  • ... memory access to some memory regions can be limited to the operating system
  • ... jumping into the operating system code from application code is only allowed to certain addresses ...
  • ... this also applies to interrupts: The operating system can decide which interrupts can be called by applications and which cannot.

If an application tries to do something which is not allowed (e.g. executing some instruction like lmsw or int $0) the CPU will cause an "Segmentation fault" interrupt (because the two bits in cs are indicating that the code does not belong to the operating system). The forbidden instruction will NOT be executed!

If you would call int $0 from a kernel driver (on 32-bit Linux; not on 64-bit Linux) this should have the same effect as a division by zero.

like image 66
Martin Rosenau Avatar answered Nov 15 '22 04:11

Martin Rosenau