Discussion:
[fpc-pascal] Branch table
Marco Borsari via fpc-pascal
2018-08-14 13:21:23 UTC
Permalink
Why the code below does exit gracefully without prints anything?
Sure, it is for my poor knowledge of the assembler, but in some details,
please...

program branch;
{$ASMMODE intel}
label next,stop,a,b,c;
var idx:byte;
begin
write('Index? ');
readln(idx);
asm
mov ax,idx;
shl ax,2;
mov bx,next;
add bx,ax;
jmp (*short*) [ebx+4];
next:
jmp a;
jmp b;
jmp c;
end['EAX','EBX'];
a:
writeln('0');
goto stop;
b:
writeln('1');
goto stop;
c:
writeln('2');
stop:
writeln('stop');
end.

Just another question: why the short modifier is unrecognized?
Thanks for any help in this holydays time,
Marco
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/list
Giuliano Colla
2018-08-16 15:40:32 UTC
Permalink
Post by Marco Borsari via fpc-pascal
Why the code below does exit gracefully without prints anything?
Sure, it is for my poor knowledge of the assembler, but in some
details, please...
program branch;
{$ASMMODE intel}
label next,stop,a,b,c;
var idx:byte;
begin
write('Index? ');
readln(idx);
asm
mov ax,idx;
shl ax,2;
mov bx,next;
add bx,ax;
jmp (*short*) [ebx+4];
jmp a;
jmp b;
jmp c;
end['EAX','EBX'];
writeln('0');
goto stop;
writeln('1');
goto stop;
writeln('2');
writeln('stop');
end.
Just another question: why the short modifier is unrecognized?
Thanks for any help in this holydays time,
Marco
I tested your code in my environment (Linux - x86_64), compiled with fpc
-g -a branch.pas. (-g is to add debug information, -a to get the
assembler listing).
Post by Marco Borsari via fpc-pascal
gdb branch
(gdb)run

The output is the following:

(gdb) run
Starting program: /home/colla/Applicazioni/Lazarus/Branch/branch
Index? 1

Program received signal SIGSEGV, Segmentation fault.
main () at branch.pas:13
13 jmp (*short*) [ebx+4];

The first thing I notice is that you load BX, which is a 16 bit register
(the lower 16 bits of EBX), with the value of "next", and then Jump to
the content of EBX which is a 32 bit register, whose lower 16 bits have
been loaded but whose upper 16 bits are undefined. A SIGSEV is therefore
to be expected. If you are in a 32 Bit environment you should use EBX,
if you're in a 64 Bit environment you should use RBX.

What I would do, if I were in your place, would be to rewrite your
program in pure Pascal, compile it with the -a switch to get the
assembler listing, and use the compiler generated assembler code as a
guideline to your optimized assembler.

Giuliano
--
Do not do to others as you would have them do to you.They might have different tastes.

_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists
Marco Borsari via fpc-pascal
2018-08-17 13:46:17 UTC
Permalink
Post by Giuliano Colla
The first thing I notice is that you load BX, which is a 16 bit register
(the lower 16 bits of EBX), with the value of "next", and then Jump to
the content of EBX which is a 32 bit register, whose lower 16 bits have
been loaded but whose upper 16 bits are undefined. A SIGSEV is therefore
to be expected. If you are in a 32 Bit environment you should use EBX,
if you're in a 64 Bit environment you should use RBX.
Thank you, I have made the correction you suggested, but I obtain a
segmentation fault again. Indeed new code is

program branch;
{$ASMMODE intel}
label next,stop,a,b,c;
var idx:byte;
begin
write('Index? ');
readln(idx);
asm
mov al,idx;
shl ax,2;
mov ebx,next;
add ebx,eax;
jmp ebx;
next:
jmp a;
jmp b;
jmp c;
end['EAX','EBX'];
a:
writeln('0');
goto stop;
b:
writeln('1');
goto stop;
c:
writeln('2');
stop:
writeln('stop');
end.

Also for what I understand jmp does not require to refer to the address
in the register.
Post by Giuliano Colla
What I would do, if I were in your place, would be to rewrite your
program in pure Pascal, compile it with the -a switch to get the
assembler listing, and use the compiler generated assembler code as a
guideline to your optimized assembler.
I found that someone made that for me at link
http://www.mindfruit.co.uk/2012/01/switch-blocks-jump-tables.html
and I have tried to rewrite the program in at&t syntax

program branch2;
{$ASMMODE att}
label next,stop,a,b,c;
var idx:byte;
begin
write('Index? ');
readln(idx);
asm
movb idx,%al
jmp *next(,%eax,4)
next:
jmp a;
jmp b;
jmp c;
end['EAX'];
a:
writeln('0');
goto stop;
b:
writeln('1');
goto stop;
c:
writeln('2');
stop:
writeln('stop');
end.

but this fails compilation at line 10 with messages
Unsupported symbol type for operand
Unknown identifier 'NEXT'
Well, I think I can live without it, it is only for
the sake of curiosity,
Marco
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/f
Giuliano Colla
2018-08-17 16:04:37 UTC
Permalink
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Marco Borsari via fpc-pascal
2018-08-18 10:27:31 UTC
Permalink
Enjoy programming!
Giuliano
Thank you!
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/
Marco Borsari via fpc-pascal
2018-08-18 13:52:26 UTC
Permalink
I modified your code, to add a jump table (as it is in the example you
mention)
I came to that

program branch;
{$ASMMODE intel}
label tab,stop,a,b,c;
var idx:byte;
begin
write('Index? ');
readln(idx);
asm
xor eax,eax;
mov al,idx;
shl ax,2;
mov ebx,tab;
add ebx,eax;
jmp ebx;
tab:
dd (*offset*) a;
dd (*offset*) b;
dd (*offset*) c;
end['EAX','EBX'];
a:
writeln('0');
goto stop;
b:
writeln('1');
goto stop;
c:
writeln('2');
stop:
writeln('stop');
end.

but it works only for index 0, and crashes otherwise. Maybe
a problem of alignment? Or must be tab declared in data section?
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http:/
Giuliano Colla
2018-08-20 15:32:04 UTC
Permalink
Post by Marco Borsari via fpc-pascal
it works only for index 0, and crashes otherwise. Maybe
a problem of alignment? Or must be tab declared in data section?
On the Intel architecture you cannot perform pointer arithmetic as if a
pointer were just a number.
A pointer is composed of two parts: a "selector" and an "offset", which
must be handled separately.

If in place of your addition (add ebx,eax) you leave the appropriate
instruction to take care of putting together selector and offset, it works.
Just change your lines:

mov ebx,tab;
add ebx,eax;
jmp ebx;


Into:

jmp tab[eax]

and it will work just fine. Just tested.

Giuliano
--
Do not do to others as you would have them do to you.They might have different tastes.

_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailma
Marco Borsari via fpc-pascal
2018-08-21 09:42:48 UTC
Permalink
Post by Giuliano Colla
On the Intel architecture you cannot perform pointer arithmetic as if a
pointer were just a number.
A pointer is composed of two parts: a "selector" and an "offset", which
must be handled separately.
Ah, I saw, 32 bit segmentation is quite complicated.
Thank you twice, Marco

_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.free
Florian Klämpfl
2018-08-23 07:32:58 UTC
Permalink
Post by Marco Borsari via fpc-pascal
Post by Giuliano Colla
On the Intel architecture you cannot perform pointer arithmetic as if a
pointer were just a number.
A pointer is composed of two parts: a "selector" and an "offset", which
must be handled separately.
Ah, I saw, 32 bit segmentation is quite complicated.
Thank you twice, Marco
I still miss the point of a hand coded branch table ...

_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc
Marco Borsari via fpc-pascal
2018-08-23 09:34:50 UTC
Permalink
On Thu, 23 Aug 2018 09:32:58 +0200
Post by Florian Klämpfl
Post by Marco Borsari via fpc-pascal
Post by Giuliano Colla
On the Intel architecture you cannot perform pointer arithmetic as if a
pointer were just a number.
A pointer is composed of two parts: a "selector" and an "offset", which
must be handled separately.
Ah, I saw, 32 bit segmentation is quite complicated.
Thank you twice, Marco
I still miss the point of a hand coded branch table ...
It would be for the Wirth optimization in the access of an array,
when the index is 0 or 1, allowing the elimination of a multiplication.

case idx of
0: (*adr:=adr*);
1: adr:=adr+lel;
end
else adr:=adr+idx*lel;

It's half for paranoia and half for the desire to learn, I am sorry,
Marco
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-p
Giuliano Colla
2018-08-26 09:43:20 UTC
Permalink
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Florian Klämpfl
2018-08-26 16:32:29 UTC
Permalink
Post by Marco Borsari via fpc-pascal
It would be for the Wirth optimization in the access of an array,
when the index is 0 or 1, allowing the elimination of a multiplication.
I'm afraid that this sort of optimization is rather outdated, and doesn't take into account a number of factors which
make modern processors behave quite differently from old times ones.
Multiplication is much less expensive then a jmp in most cases on today's CPUs.

It is even the other way round, it is often useful to replace an if statement by a multiplication like:

if a>b then
Inc(c,d);

can be replaced on modern CPUs by

Inc(c,d*ord(a>b));
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.freepascal.org/cgi-b
Marco Borsari via fpc-pascal
2018-08-27 07:51:54 UTC
Permalink
On Sun, 26 Aug 2018 18:32:29 +0200
Post by Florian Klämpfl
Post by Marco Borsari via fpc-pascal
It would be for the Wirth optimization in the access of an array,
when the index is 0 or 1, allowing the elimination of a multiplication.
I'm afraid that this sort of optimization is rather outdated, and doesn't take into account a number of factors which
make modern processors behave quite differently from old times ones.
Multiplication is much less expensive then a jmp in most cases on today's CPUs.
if a>b then
Inc(c,d);
can be replaced on modern CPUs by
Inc(c,d*ord(a>b));
Ah I see, anyway I did not think that, as Giuliano said, beacuse of alignment of
array element, the multiplication is already substituded by a shift, and the essence
of a branch table becomes superflous. Thank you for your time,
Marco
_______________________________________________
fpc-pascal maillist - fpc-***@lists.freepascal.org
http://lists.fre

Loading...