Skip to contentSkip to conversation

interesting linker behaviour :)

parisc-linux Randolph Chung 3 participants 11 messages Sep 21, 2004

lore
Share & tools
lore
#0 lore raw

willy found a problem this morning with the exception code which was traced down to the following:

the following code comes from lusercopy.S (with macros expanded):

lstrncpy_from_user:

        .proc
        .callinfo NO_CALLS
        .entry
        comib,=     0,%r24,$lsfu_done
        copy        %r24,%r23
        get_sr
1:      ldbs,ma     1(%sr1,%r25),%r1
$lsfu_loop:
        stbs,ma     %r1,1(%r26)
        comib,=,n   0,%r1,$lsfu_done
        addib,<>,n  -1,%r24,$lsfu_loop
2:      ldbs,ma     1(%sr1,%r25),%r1
$lsfu_done:
        sub         %r23,%r24,%r28
$lsfu_exit:
        bv          %r0(%r2)
        nop
        .exit

        .section .fixup,"ax"
3:      b $lsfu_exit
        ldi         -EFAULT,%r28
        .previous

        .section __ex_table,"aw"
        .word       1b,3b
        .word       2b,3b
        .previous

        .procend

what is supposed to happen is that when a fault happens at "1:", we would branch to "3:". The code in "3:" sets the return value to -EFAULT and branches back to the exit path.

what we observed was that when a fault happens, we get an endless loop of faults.

when i disassembled the code at 3:, i see:

1038ce68:       e8 05 00 7d     b,l 10357eac <tcpdiag_dump+0x5ac>,r0
1038ce6c:       34 1c 3f e5     ldi -e,ret0

the target of the branch is a long branch stub:

10357eac:       20 20 02 02     ldil 10100000,r1
10357eb0:       e0 20 22 b2     be,n 158(sr4,r1)

but 10100158 is lstrncpy_from_user, not $lsfu_exit:
10100158 <lstrncpy_from_user>
10100190 <$lsfu_exit>

i wonder if the sections are somehow confusing things.... this is with fairly recent gcc/binutils toolchains, for 32-bit.

randolph

Signature · 7 lines
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#1 lore raw
Quoted 6 lines · Randolph Chung

but 10100158 is lstrncpy_from_user, not $lsfu_exit:
10100158 <lstrncpy_from_user>
10100190 <$lsfu_exit>

i wonder if the sections are somehow confusing things.... this is with fairly recent gcc/binutils toolchains, for 32-bit.

Multiple entry points to a function may not work if an import stub is required? The import stubs are thrown into a hash, and it probably thinks it's okay for you to use the same import stub. You on the other want a second entry point.

I recommend you give the exit it's own symbol, .export and .import the linker thinks it's two different functions?

c.

_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

#2 lore raw
Quoted 8 lines · Carlos O'Donell
Quoted 6 lines · Randolph Chung

but 10100158 is lstrncpy_from_user, not $lsfu_exit:
10100158 <lstrncpy_from_user>
10100190 <$lsfu_exit>

i wonder if the sections are somehow confusing things.... this is with fairly recent gcc/binutils toolchains, for 32-bit.

Quoted 7 lines

Multiple entry points to a function may not work if an import stub is required? The import stubs are thrown into a hash, and it probably thinks it's okay for you to use the same import stub. You on the other want a second entry point.

I recommend you give the exit it's own symbol, .export and .import the linker thinks it's two different functions?

Wow. I need to stop and re-read my emails.

a. Multiple entry points to a function, and import stubs probably don't
mix well.

b. Define a symbol for lsfu_exit, .export it, then .import it later
and branch to that symbol. We want the linker to think it's two different functions.

I think that is clearer? :)

c.

_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

#3 lore raw
In reply to Carlos O'Donell
Quoted 8 lines · Randolph Chung
Quoted 6 lines

but 10100158 is lstrncpy_from_user, not $lsfu_exit:
10100158 <lstrncpy_from_user>
10100190 <$lsfu_exit>

i wonder if the sections are somehow confusing things.... this is with fairly recent gcc/binutils toolchains, for 32-bit.

Quoted 7 lines

Multiple entry points to a function may not work if an import stub is required? The import stubs are thrown into a hash, and it probably thinks it's okay for you to use the same import stub. You on the other want a second entry point.

I recommend you give the exit it's own symbol, .export and .import the linker thinks it's two different functions?

Good catch! I've hit this problem before but under HP-UX. GAS doesn't support the alternate entry point fixup needed to support multiple entry points to a function. I don't think anyone has tried to support this with the ELF tools. There could be some nasty interactions with the HP unwind data when you start adding multiple entry points to a function.

I haven't looked at this in detail but possibly you can change the fixup table to contain pc-relative offsets. I looked at this when I reworked the casesi pattern in GCC a few months ago. This makes the table smaller and in many cases the number of instructions is less than that with branches in the table (particularly for the PIC case). I ended up putting the table in the same section as the text since in that case the offsets were absolute. However, I did look at putting the offsets in readonly data. This is where I came up with the method to create 32 and 64-bit pc-relative offsets. It takes a couple of extra instructions to load the address of a table that's in a different section. As a side, I believe that only 32-bit offsets are needed in the 64-bit runtime.

Dave

Signature · 6 lines
J. David Anglin                                  [email protected]
National Research Council of Canada              (613) 990-0752 (FAX: 952-6602)
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#4 lore raw
Quoted 6 lines

Good catch! I've hit this problem before but under HP-UX. GAS doesn't support the alternate entry point fixup needed to support multiple entry points to a function. I don't think anyone has tried to support this with the ELF tools. There could be some nasty interactions with the HP unwind data when you start adding multiple entry points to a function.

yeah, it will break unwinding :(

Quoted 6 lines

I haven't looked at this in detail but possibly you can change the fixup table to contain pc-relative offsets. I looked at this when I reworked the casesi pattern in GCC a few months ago. This makes the table smaller and in many cases the number of instructions is less than that with branches in the table (particularly for the PIC case).

well, this is what we used to do, but we don't do this now because it requires us to be able to do a pc-relative calculation between code in two different sections (text and fixup), and GAS doesn't allow that either.

for now i'm using the solution we are using for 64-bit code, which is to use a manually created long-branch stub (ldil/ldo/bv). since this is anyway in a slow-path the performance hit is probably negligible.

randolph

Signature · 7 lines
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#5 lore raw
Quoted 11 lines
Quoted 6 lines

I haven't looked at this in detail but possibly you can change the fixup table to contain pc-relative offsets. I looked at this when I reworked the casesi pattern in GCC a few months ago. This makes the table smaller and in many cases the number of instructions is less than that with branches in the table (particularly for the PIC case).

well, this is what we used to do, but we don't do this now because it requires us to be able to do a pc-relative calculation between code in two different sections (text and fixup), and GAS doesn't allow that either.

GAS does allow you to do it. If you look in GCC, you will see that we use the special assembler symbol $PIC_pcrel$0 to create pc-relative relocations. To create a jump table with 32-bit pc-relative relocations, you would do something like this:

L$0:

	.word L$1+(.+8-L$0)-$PIC_pcrel$0
	.word L$2+(.+8-L$0)-$PIC_pcrel$0
	...

The assembler is sensitive to the ordering of the terms in the expression.

Basically, $PIC_pcrel$0 == .+8 in each expression, so you are just left with the difference of labels in the final evaluation. Note that (.+8-L$0) evaluates to an absolute constant. Thus, the first two terms are just a symbol plus a constant addend. GAS will allow that.

Dave

Signature · 6 lines
J. David Anglin                                  [email protected]
National Research Council of Canada              (613) 990-0752 (FAX: 952-6602)
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#6 lore raw
In reply to Randolph Chung
Quoted 3 lines

for now i'm using the solution we are using for 64-bit code, which is to use a manually created long-branch stub (ldil/ldo/bv). since this is anyway in a slow-path the performance hit is probably negligible.

As I suggested before, you can shorten (ldil/ldo/bv) to (ldil/be) if if you know which space register to use in the be (in user space, %sr4 will always work since the address space is flat).

The linker doesn't insert stubs for the (ldil/be) sequence although possibly it should.

The code sequence to handle 32-bit pc-relative offsets is going to be longer than either of the above two sequences. So, possibly you would only want to go this route if the table is large.

Dave

Signature · 6 lines
J. David Anglin                                  [email protected]
National Research Council of Canada              (613) 990-0752 (FAX: 952-6602)
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#7 lore raw
Quoted 3 lines

As I suggested before, you can shorten (ldil/ldo/bv) to (ldil/be) if if you know which space register to use in the be (in user space, %sr4 will always work since the address space is flat).

erm, yes, you did say that, and i forgot. i will change it.

randolph

Signature · 7 lines
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux
#8 lore raw
In reply to John David Anglin
Quoted 16 lines · John David Anglin
Quoted 8 lines · Randolph Chung
Quoted 6 lines

but 10100158 is lstrncpy_from_user, not $lsfu_exit:
10100158 <lstrncpy_from_user>
10100190 <$lsfu_exit>

i wonder if the sections are somehow confusing things.... this is with fairly recent gcc/binutils toolchains, for 32-bit.

Quoted 7 lines

Multiple entry points to a function may not work if an import stub is required? The import stubs are thrown into a hash, and it probably thinks it's okay for you to use the same import stub. You on the other want a second entry point.

I recommend you give the exit it's own symbol, .export and .import the linker thinks it's two different functions?

Quoted 6 lines

Good catch! I've hit this problem before but under HP-UX. GAS doesn't support the alternate entry point fixup needed to support multiple entry points to a function. I don't think anyone has tried to support this with the ELF tools. There could be some nasty interactions with the HP unwind data when you start adding multiple entry points to a function.

I think you said we had similar problems with non-local goto's?

Either we had a conversation about multiple entry points, or I read it in one of the HP documents :)

c.

_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux

#10 lore raw
In reply to Carlos O'Donell
Quoted 8 lines
Quoted 6 lines

Good catch! I've hit this problem before but under HP-UX. GAS doesn't support the alternate entry point fixup needed to support multiple entry points to a function. I don't think anyone has tried to support this with the ELF tools. There could be some nasty interactions with the HP unwind data when you start adding multiple entry points to a function.

I think you said we had similar problems with non-local goto's?

Right, that's where it came up. As of 6/11/04, we have a new nonlocal_goto expander. I'm a little foggy on this issue but I think prior to the tree-ssa merge the default nonlocal_goto expander was ok.

Dave

Signature · 6 lines
J. David Anglin                                  [email protected]
National Research Council of Canada              (613) 990-0752 (FAX: 952-6602)
_______________________________________________
parisc-linux mailing list
[email protected]
http://lists.parisc-linux.org/mailman/listinfo/parisc-linux