Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2018-08

Branch table

13 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Marco Borsari

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

Reply by email

Giuliano Colla
to Marco Borsari

Il 14/08/2018 15:21, Marco Borsari via fpc-pascal ha scritto:

Show quoted text 37 lines
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

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).
Then launched it with gdb debugger:

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.

Reply by email

Marco Borsari
to Giuliano Colla

Il 16/08/2018 17:40, Giuliano Colla ha scritto:

Show quoted text 6 lines
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.

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

Reply by email

Marco Borsari
to Giuliano Colla:

Il 17/08/2018 18:04, Giuliano Colla ha scritto:

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?

Reply by email

Giuliano Colla
to Marco Borsari

Il 18/08/2018 15:52, Marco Borsari via fpc-pascal ha scritto:

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.

Reply by email

Marco Borsari
to Giuliano Colla

Il 20/08/2018 17:32, Giuliano Colla ha scritto:

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

Reply by email

Florian Klämpfl
to Marco Borsari
Marco Borsari wrote 9 lines
Il 20/08/2018 17:32, Giuliano Colla ha scritto: > 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 ...

Reply by email

Marco Borsari
to Florian Klämpfl
Show quoted text 12 lines
Am 21.08.2018 um 11:42 schrieb Marco Borsari via fpc-pascal: > Il 20/08/2018 17:32, Giuliano Colla ha scritto: > >> 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

Reply by email

Florian Klämpfl
to Giuliano Colla
Giuliano Colla wrote 7 lines
Il 23/08/2018 11:34, Marco Borsari via fpc-pascal ha scritto: > 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));

Reply by email

Marco Borsari
to Florian Klämpfl
Show quoted text 19 lines
Am 26.08.2018 um 11:43 schrieb Giuliano Colla: > Il 23/08/2018 11:34, Marco Borsari via fpc-pascal ha scritto: > >> 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));

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

Reply by email