I'm trying to write byte 0xff
to the parallel port at 0x378
. It compiles and links without issue, but segfaults at the OUTSB
instruction.
section .text
global _start
_err_exit:
mov eax, 1
mov ebx, 1
int 80h
_start:
mov eax, 101 ; ioperm
mov ebx, 0x378 ; Parallel port addr
mov ecx, 2 ; number of bytes to 'unlock'
mov edx, 1 ; enable
int 80h
mov esi, 0xff
mov dx, 0x378
outsb
mov eax, 1 ; exit
mov ebx, 0
int 80h
If I step through it with GDB and check the registers just before the OUTSB
instruction, it doesn't look like there is anything in the DX register? or dx
== edx
in 32bit?
(gdb) info registers
eax 0x0 0
ecx 0x2 2
edx 0x378 888
ebx 0x378 888
esp 0xffffd810 0xffffd810
ebp 0x0 0x0
esi 0xff 255
edi 0x0 0
eip 0x8048090 0x8048090 <_start+36>
eflags 0x246 [ PF ZF IF ]
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
What am I doing wrong here?
(info on the OUTS instructions: http://siyobik.info/main/reference/instruction/OUTS%2FOUTSB%2FOUTSW%2FOUTSD)
EDIT:
The C version of the program works:
int main(int argc, char *argv[])
{
int addr = 0x378;
int result = ioperm(addr,5,1);
outb(0xff, addr);
}
There is a number of issues with that code. Firstly, you seem to forget that OUTSB
is a privileged instruction, i.e. it can be executed only if the calling process has ring 0 access, i.e. it's a part of the kernel code. As far as I'm aware, the only code in Linux that has access to privileged instructions is the kernel itself, and the modules that it loads. All the other processes will give you a Segmentation fault
(which is actually a General Protection Fault
signalled by the CPU) when you try to execute a privileged instruction from a nonprivileged segment of code. I don't know how calling the ioperm
syscall influences that, though.
Secondly, OUTSB
writes a byte from a memory location specified by ESI
to the I/O port in DX
. In this case, you're telling the processor to write data to the port from location 0xff
, to which the process surely doesn't have access. You can simplify that by simply changing the code to use the OUT
instruction, since OUTSB
is rather meant to be used with the REP
prefix. Try this :
mov al, 0xff
out 0x378, al
This outputs the byte in al
to the I/O port specified by the immediate operand, in this case 0x378
.
Let me know how that turned out.