Created attachment 11375 [details] test case Out of sudden my prog started to randomly crash on i386 target. It appears the combination of options -no-pie -export-dynamic causes ld to randomly corrupt the code section. Attached is the fully automated test-case. Just type "make" - it will link the executable and look with gdb at the assembler in one particular place where I spotted the corruption. It will then print "TEST FAILED!". You can run "make good" that will do the same but without -export-dynamic. This will end up in "TEST PASSED!". gold has no such problem.
dpmi.o has: 8f69: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax 8f6b: R_386_GOT32X DPMI_return_from_realmode 8f6f: 66 05 00 48 add $0x4800,%ax 8f73: 66 2b 83 00 00 00 00 sub 0x0(%ebx),%ax 8f76: R_386_GOT32X DPMI_dummy_start 8f7a: 66 89 46 30 mov %ax,0x30(%esi) Only the lower 16 bits of GOT slot are used. It leads to: [hjl@gnu-cfl-1 pr23854]$ cat pr23854.s .data .type bar, @object bar: .byte 1 .size bar, .-bar .globl foo .type foo, @object foo: .byte 1 .size foo, .-foo .text .globl _start .type _start, @function _start: adcw bar@GOT(%ecx), %ax addw bar@GOT(%ecx), %bx andw bar@GOT(%ecx), %cx cmpw bar@GOT(%ecx), %dx orw bar@GOT(%ecx), %di sbbw bar@GOT(%ecx), %si subw bar@GOT(%ecx), %bp xorw bar@GOT(%ecx), %sp testw %cx, bar@GOT(%ecx) adcw foo@GOT(%ecx), %ax addw foo@GOT(%ecx), %bx andw foo@GOT(%ecx), %cx cmpw foo@GOT(%ecx), %dx orw foo@GOT(%ecx), %di sbbw foo@GOT(%ecx), %si subw foo@GOT(%ecx), %bp xorw foo@GOT(%ecx), %sp testw %cx, foo@GOT(%ecx) .size _start, .-_start [hjl@gnu-cfl-1 pr23854]$ make as --32 -o pr23854.o pr23854.s ld -melf_i386 -o pr23854 pr23854.o [hjl@gnu-cfl-1 pr23854]$ objdump -dw pr23854 pr23854: file format elf32-i386 Disassembly of section .text: 08049000 <_start>: 8049000: 66 81 d0 00 a0 adc $0xa000,%ax 8049005: 04 08 add $0x8,%al 8049007: 66 81 c3 00 a0 add $0xa000,%bx 804900c: 04 08 add $0x8,%al 804900e: 66 81 e1 00 a0 and $0xa000,%cx 8049013: 04 08 add $0x8,%al 8049015: 66 81 fa 00 a0 cmp $0xa000,%dx 804901a: 04 08 add $0x8,%al 804901c: 66 81 cf 00 a0 or $0xa000,%di 8049021: 04 08 add $0x8,%al 8049023: 66 81 de 00 a0 sbb $0xa000,%si 8049028: 04 08 add $0x8,%al 804902a: 66 81 ed 00 a0 sub $0xa000,%bp 804902f: 04 08 add $0x8,%al 8049031: 66 81 f4 00 a0 xor $0xa000,%sp 8049036: 04 08 add $0x8,%al 8049038: 66 f7 c1 00 a0 test $0xa000,%cx 804903d: 04 08 add $0x8,%al 804903f: 66 81 d0 01 a0 adc $0xa001,%ax 8049044: 04 08 add $0x8,%al 8049046: 66 81 c3 01 a0 add $0xa001,%bx 804904b: 04 08 add $0x8,%al 804904d: 66 81 e1 01 a0 and $0xa001,%cx 8049052: 04 08 add $0x8,%al 8049054: 66 81 fa 01 a0 cmp $0xa001,%dx 8049059: 04 08 add $0x8,%al 804905b: 66 81 cf 01 a0 or $0xa001,%di 8049060: 04 08 add $0x8,%al 8049062: 66 81 de 01 a0 sbb $0xa001,%si 8049067: 04 08 add $0x8,%al 8049069: 66 81 ed 01 a0 sub $0xa001,%bp 804906e: 04 08 add $0x8,%al 8049070: 66 81 f4 01 a0 xor $0xa001,%sp 8049075: 04 08 add $0x8,%al 8049077: 66 f7 c1 01 a0 test $0xa001,%cx 804907c: 04 08 add $0x8,%al [hjl@gnu-cfl-1 pr23854]$ Does dpmi.o contain normal i386 code?
(In reply to H.J. Lu from comment #1) > dpmi.o has: > > 8f69: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax 8f6b: > R_386_GOT32X DPMI_return_from_realmode > 8f6f: 66 05 00 48 add $0x4800,%ax > 8f73: 66 2b 83 00 00 00 00 sub 0x0(%ebx),%ax 8f76: > R_386_GOT32X DPMI_dummy_start > 8f7a: 66 89 46 30 mov %ax,0x30(%esi) These functions are not from dpmi.c, they are from another translation unit. The function of interest is "do_dpmi_int" - it gets corrupted, as my test-case shows. > Does dpmi.o contain normal i386 code? Yes, but not the ones you pointed to. These should be undefined in dpmi.c, and are actually written in 16bit asm. Please inspect "do_dpmi_int" instead - it is a valid C func from dpmi.o. You can see from my .gdbinit script where the corruption actually happens.
(In reply to Stas Sergeev from comment #2) > (In reply to H.J. Lu from comment #1) > > dpmi.o has: > > > > 8f69: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax 8f6b: > > R_386_GOT32X DPMI_return_from_realmode > > 8f6f: 66 05 00 48 add $0x4800,%ax > > 8f73: 66 2b 83 00 00 00 00 sub 0x0(%ebx),%ax 8f76: > > R_386_GOT32X DPMI_dummy_start > > 8f7a: 66 89 46 30 mov %ax,0x30(%esi) > These functions are not from dpmi.c, they > are from another translation unit. The function > of interest is "do_dpmi_int" - it gets corrupted, > as my test-case shows. > > > Does dpmi.o contain normal i386 code? > Yes, but not the ones you pointed to. > These should be undefined in dpmi.c, and > are actually written in 16bit asm. > Please inspect "do_dpmi_int" instead - it > is a valid C func from dpmi.o. > You can see from my .gdbinit script where > the corruption actually happens. do_dpmi_int has 8f69: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax 8f6b: R_386_GOT32X DPMI_return_from_realmode 8f6f: 66 05 00 48 add $0x4800,%ax 8f73: 66 2b 83 00 00 00 00 sub 0x0(%ebx),%ax 8f76: R_386_GOT32X DPMI_dummy_start 8f7a: 66 89 46 30 mov %ax,0x30(%esi) 8f7e: 0f b7 45 2c movzwl 0x2c(%ebp),%eax Please show me the corresponding C code.
(In reply to H.J. Lu from comment #3) > do_dpmi_int has Ah, I see now what you mean. > 8f69: 8b 83 00 00 00 00 mov 0x0(%ebx),%eax 8f6b: > R_386_GOT32X DPMI_return_from_realmode > 8f6f: 66 05 00 48 add $0x4800,%ax > 8f73: 66 2b 83 00 00 00 00 sub 0x0(%ebx),%ax 8f76: > R_386_GOT32X DPMI_dummy_start > 8f7a: 66 89 46 30 mov %ax,0x30(%esi) > 8f7e: 0f b7 45 2c movzwl 0x2c(%ebp),%eax > > Please show me the corresponding C code. Of course: https://github.com/stsp/dosemu2/blob/devel/src/dosext/dpmi/dpmi.c#L2053 The function is called "do_int31", but it gets inlined into do_dpmi_int. This is exactly the line you look for. The ugly macros are here: https://github.com/stsp/dosemu2/blob/devel/src/include/cpu.h#L138 https://github.com/stsp/dosemu2/blob/devel/src/include/bios.h#L161 I will also try to attach the dpmi.s with -verbose-asm for you tomorrow.
Basically this code calculates the distance between "DPMI_return_from_realmode" and "DPMI_dummy_start", and puts the result into a 16bit variable. That explains the use of %ax. Its possible because those funcs are in 16bit asm. I think the gcc-generated asm code is perfectly fine here. It optimized the 32bit calculus to 16bits.
Please provide pre-processed dpmi.c from gcc -E and command-line options to generate dpmi.s
Created attachment 11379 [details] verbose asm > Please provide pre-processed dpmi.c from gcc -E and command-line > options to generate dpmi.s Unfortunately the problem only happens on a 32bit machine, I can't reproduce it with multilib on my 64bit one. So I'll provide what you ask for, later, when I get an access to the target machine. For now, here you have a verbose asm output. It seems the command line is also printed there, or at least its part.
Created attachment 11381 [details] preprocessed output
(In reply to H.J. Lu from comment #6) > Please provide pre-processed dpmi.c from gcc -E and command-line > options to generate dpmi.s gcc -xc -S -fverbose-asm -O -o dpmi.s dpmi.E gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04) Btw, could you please explain why the problem only happens with -export-dynamic? This doesn't seem to be related to the generated asm, AFAICT.
[hjl@gnu-cfl-1 pr23854]$ cat x.c extern void foo (void); short foo_p (void) { return 0x400 - (int) &foo; } [hjl@gnu-cfl-1 pr23854]$ cat foo.c extern short foo_p (void); __attribute__ ((visibility("hidden"))) void foo (void) { } void _start (void) { foo_p (); } [hjl@gnu-cfl-1 pr23854]$ make gcc -m32 -B./ -O2 -fPIE -c -o x.o x.c gcc -m32 -B./ -O2 -fPIE -c -o foo.o foo.c ld -melf_i386 -o x x.o foo.o [hjl@gnu-cfl-1 pr23854]$ objdump -dw x.o x.o: file format elf32-i386 Disassembly of section .text: 00000000 <foo_p>: 0: e8 fc ff ff ff call 1 <foo_p+0x1> 5: 81 c2 02 00 00 00 add $0x2,%edx b: b8 00 04 00 00 mov $0x400,%eax 10: 66 2b 82 00 00 00 00 sub 0x0(%edx),%ax 17: c3 ret Disassembly of section .text.__x86.get_pc_thunk.dx: 00000000 <__x86.get_pc_thunk.dx>: 0: 8b 14 24 mov (%esp),%edx 3: c3 ret [hjl@gnu-cfl-1 pr23854]$ objdump -dw x x: file format elf32-i386 Disassembly of section .text: 08049000 <foo_p>: 8049000: e8 13 00 00 00 call 8049018 <__x86.get_pc_thunk.dx> 8049005: 81 c2 fb 2f 00 00 add $0x2ffb,%edx 804900b: b8 00 04 00 00 mov $0x400,%eax 8049010: 66 81 e8 20 90 sub $0x9020,%ax 8049015: 04 08 add $0x8,%al 8049017: c3 ret 08049018 <__x86.get_pc_thunk.dx>: 8049018: 8b 14 24 mov (%esp),%edx 804901b: c3 ret 804901c: 66 90 xchg %ax,%ax 804901e: 66 90 xchg %ax,%ax 08049020 <foo>: 8049020: c3 ret 8049021: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi 8049028: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi 804902f: 90 nop 08049030 <_start>: 8049030: 53 push %ebx 8049031: e8 13 00 00 00 call 8049049 <__x86.get_pc_thunk.bx> 8049036: 81 c3 ca 2f 00 00 add $0x2fca,%ebx 804903c: 83 ec 08 sub $0x8,%esp 804903f: e8 bc ff ff ff call 8049000 <foo_p> 8049044: 83 c4 08 add $0x8,%esp 8049047: 5b pop %ebx 8049048: c3 ret 08049049 <__x86.get_pc_thunk.bx>: 8049049: 8b 1c 24 mov (%esp),%ebx 804904c: c3 ret [hjl@gnu-cfl-1 pr23854]$
(In reply to Stas Sergeev from comment #9) > (In reply to H.J. Lu from comment #6) > > Please provide pre-processed dpmi.c from gcc -E and command-line > > options to generate dpmi.s > gcc -xc -S -fverbose-asm -O -o dpmi.s dpmi.E Please add -fno-pie as workaround. > gcc version 7.3.0 (Ubuntu 7.3.0-27ubuntu1~18.04) > > Btw, could you please explain why the problem > only happens with -export-dynamic? This doesn't > seem to be related to the generated asm, AFAICT. It has nothing to do with -export-dynamic. My testcase doesn't use -export-dynamic.
(In reply to H.J. Lu from comment #11) > Please add -fno-pie as workaround. Done. This works properly. Thank you. > > Btw, could you please explain why the problem > > only happens with -export-dynamic? This doesn't > > seem to be related to the generated asm, AFAICT. > It has nothing to do with -export-dynamic. My testcase doesn't use > -export-dynamic. But my does, and in fact, when you type "make good", the only things that changes, is no -export-dynamic. Could you please make sure I am not hitting the second bug here?
(In reply to Stas Sergeev from comment #12) > > > Btw, could you please explain why the problem > > > only happens with -export-dynamic? This doesn't > > > seem to be related to the generated asm, AFAICT. > > It has nothing to do with -export-dynamic. My testcase doesn't use > > -export-dynamic. > But my does, and in fact, when you type "make good", > the only things that changes, is no -export-dynamic. > Could you please make sure I am not hitting the second > bug here? Your check for "good" one is incomplete. I got Dump of assembler code from 0x814bd49 to 0x814bd86: 0x0814bd49 <do_dpmi_int+6144>: c7 c0 eb f5 13 08 mov $0x813f5eb,%eax 0x0814bd4f <do_dpmi_int+6150>: 66 05 00 48 add $0x4800,%ax 0x0814bd53 <do_dpmi_int+6154>: 66 81 e8 e0 f5 sub $0xf5e0,%ax 0x0814bd58 <do_dpmi_int+6159>: 13 08 adc (%eax),%ecx <<<< This is wrong. 0x0814bd5a <do_dpmi_int+6161>: 66 89 46 30 mov %ax,0x30(%esi) 0x0814bd5e <do_dpmi_int+6165>: 0f b7 45 2c movzwl 0x2c(%ebp),%eax 0x0814bd62 <do_dpmi_int+6169>: 66 3d 01 03 cmp $0x301,%ax 0x0814bd66 <do_dpmi_int+6173>: 0f 84 90 00 00 00 je 0x814bdfc <do_dpmi_int+6323> 0x0814bd6c <do_dpmi_int+6179>: 66 3d 02 03 cmp $0x302,%ax 0x0814bd70 <do_dpmi_int+6183>: 0f 84 a4 00 00 00 je 0x814be1a <do_dpmi_int+6353> 0x0814bd76 <do_dpmi_int+6189>: 66 3d 00 03 cmp $0x300,%ax 0x0814bd7a <do_dpmi_int+6193>: 0f 85 9a ec ff ff jne 0x814aa1a <do_dpmi_int+1233> 0x0814bd80 <do_dpmi_int+6199>: 80 7d 20 21 cmpb $0x21,0x20(%ebp) 0x0814bd84 <do_dpmi_int+6203>: 74 3b je 0x814bdc1 <do_dpmi_int+6264> End of assembler dump.
> H.J. Lu <hjl.tools at gmail dot com> changed: > > What |Removed |Added > ---------------------------------------------------------------------------- > Component|ld |gas Sorry for being pedantic, but there is no such problem with gold. So while gas may be involved too, I wonder are you sure there is no bug in ld itself.
(In reply to Stas Sergeev from comment #14) > > H.J. Lu <hjl.tools at gmail dot com> changed: > > > > What |Removed |Added > > ---------------------------------------------------------------------------- > > Component|ld |gas > Sorry for being pedantic, but there is no > such problem with gold. So while gas may be gold != ld > involved too, I wonder are you sure there is > no bug in ld itself. Please try: https://sourceware.org/ml/binutils/2018-11/msg00021.html You need to compile with the new assembler.
> H.J. Lu <hjl.tools at gmail dot com> changed: > Please try: > > https://sourceware.org/ml/binutils/2018-11/msg00021.html > > You need to compile with the new assembler. Building your git now... However. Are there really no hopes to link these already existing objects properly? gold have no problems with those, and if you consider them "broken" to the point that it isn't worth an efforts, then maybe at least ld can detect the problem and error out? Because its exactly ld that corrupted the instructions, and I really am surprised you didn't even put any small band-aid to stop it from ever doing so.
(In reply to Stas Sergeev from comment #16) > > H.J. Lu <hjl.tools at gmail dot com> changed: > > Please try: > > > > https://sourceware.org/ml/binutils/2018-11/msg00021.html > > > > You need to compile with the new assembler. > Building your git now... > However. Are there really no hopes to link > these already existing objects properly? > gold have no problems with those, and if you Old binutils also didn't have this issue. > consider them "broken" to the point that it > isn't worth an efforts, then maybe at least > ld can detect the problem and error out? > Because its exactly ld that corrupted the > instructions, and I really am surprised you > didn't even put any small band-aid to stop > it from ever doing so. Your code doesn't conform to i386 psABI, which doesn't support only using lower 16 bits of GOT entries.
The master branch has been updated by H.J. Lu <hjl@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=a4749e56cacefdc1a571231744a9b87a3f5458b9 commit a4749e56cacefdc1a571231744a9b87a3f5458b9 Author: H.J. Lu <hjl.tools@gmail.com> Date: Mon Nov 5 11:12:28 2018 -0800 Correct ChangeLog entries for PR gas/23854 commit commit e60f4d3bdac25f02875afe36b7436bc2dfbbb978 Author: H.J. Lu <hjl.tools@gmail.com> Date: Mon Nov 5 09:01:26 2018 -0800 x86: Disable GOT relaxation with data prefix Since linker GOT relaxation isn't valid for 16-bit GOT access, we should disable GOT relaxation with data prefix.
> H.J. Lu <hjl.tools at gmail dot com> changed: > Your code doesn't conform to i386 psABI, which doesn't > support only using lower 16 bits of GOT entries. I would understand if linker writes me such an error. Silently producing corrupted binaries is the sign of low quality software. You can add checks, error messages, but never let the broken output...
I disasmed and diffed the object files without and with your patch. I see a lot of: --- 597,598c597,598 < 745: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi < 749: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi --- > 745: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi > 74c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi --- Is this correct, that it now applies lea to %esi twice? As %esi is used as both arg and result, I think it will be modified twice, and so I can't imagine those changes lead to an equivalent code.
(In reply to Stas Sergeev from comment #19) > > H.J. Lu <hjl.tools at gmail dot com> changed: > > Your code doesn't conform to i386 psABI, which doesn't > > support only using lower 16 bits of GOT entries. > I would understand if linker writes me such an error. > Silently producing corrupted binaries is the sign of > low quality software. You can add checks, error messages, > but never let the broken output... What your code did is outside of scope of i386 psABI.
(In reply to Stas Sergeev from comment #20) > I disasmed and diffed the object files > without and with your patch. I see a lot of: > --- > 597,598c597,598 > < 745: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi > < 749: 8d bc 27 00 00 00 00 lea 0x0(%edi,%eiz,1),%edi > --- > > 745: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi > > 74c: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi > --- > > Is this correct, that it now applies lea to > %esi twice? As %esi is used as both arg and > result, I think it will be modified twice, > and so I can't imagine those changes lead to > an equivalent code. These are NOPs.
> What your code did is outside of scope of i386 psABI. Why not linker tells me so with an error msg?
(In reply to Stas Sergeev from comment #23) > > What your code did is outside of scope of i386 psABI. > > Why not linker tells me so with an error msg? There are many corner cases linker doesn't check. You have things like extern void foo (void); short foo_p (void) { return 0x400 - (int) &foo; } In normal i386 case, &foo is 32 bits, especially with PIE. BTW, does your code work without -no-pie using ANY linkers?
> What your code did is outside of scope of i386 psABI. Why not linker tells me so with an error msg?(In reply to H.J. Lu from comment #24) > (In reply to Stas Sergeev from comment #23) > > > What your code did is outside of scope of i386 psABI. > > > > Why not linker tells me so with an error msg? > > There are many corner cases linker doesn't check. But in this particular case, when it overwrites the instructions with something else, it _could_ have checked. :( I don't think other unchecked corner cases give that level of breakage and difficulty to debug. > You have things like > > extern void foo (void); > > short > foo_p (void) > { > return 0x400 - (int) &foo; > } > > In normal i386 case, &foo is 32 bits, especially with PIE. BTW, > does your code work without -no-pie using ANY linkers? You mean, any other than ld, or including ld? In fact, I added -no-pie just very recently: https://github.com/stsp/dosemu2/commit/d5eb51320477f32df7deb9161fa728e12bcd06dd to get the high load address. Before that, it definitely worked with ld, and most likely also with gold (but I haven't checked gold for quite some time). Note that older ubuntu distros (and likely others) used no-pie by default. ubuntu defaulted to pie only in 18.04 or so, which started to give me the low load address again.
By the way, is it a feature of this bugzilla to open the entirely different bug ticket after I post any comment? This always makes me worry that I posted to wrong thread. For example, when I post to _this_ ticket, bugzilla opens ticket 14187.
Customize "After changing a bug" in userprefs.
The binutils-2_31-branch branch has been updated by H.J. Lu <hjl@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1929a39655d77686385913ef63c6c4340bb2d729 commit 1929a39655d77686385913ef63c6c4340bb2d729 Author: H.J. Lu <hjl.tools@gmail.com> Date: Mon Nov 5 09:01:26 2018 -0800 x86: Disable GOT relaxation with data prefix Since linker GOT relaxation isn't valid for 16-bit GOT access, we should disable GOT relaxation with data prefix. gas/ PR gas/23854 * config/tc-i386.c (output_disp): Disable GOT relaxation with data prefix. * testsuite/gas/i386/mixed-mode-reloc32.d: Updated. ld/ PR gas/23854 * testsuite/ld-i386/i386.exp: Run pr23854. * testsuite/ld-x86-64/x86-64.exp: Likewwise. * testsuite/ld-i386/pr23854.d: New file. * testsuite/ld-i386/pr23854.s: Likewwise. * testsuite/ld-i386/pr23854.d: Likewwise. * testsuite/ld-x86-64/pr23854.d: Likewwise. * testsuite/ld-x86-64/pr23854.s: Likewwise. (cherry picked from commit e60f4d3bdac25f02875afe36b7436bc2dfbbb978)
Fixed for 2.32 and 2.31 branch.
The binutils-2_30-branch branch has been updated by H.J. Lu <hjl@sourceware.org>: https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3050b43068674882b01a51351c5c39e950f0ee41 commit 3050b43068674882b01a51351c5c39e950f0ee41 Author: H.J. Lu <hjl.tools@gmail.com> Date: Mon Nov 5 09:01:26 2018 -0800 x86: Disable GOT relaxation with data prefix Since linker GOT relaxation isn't valid for 16-bit GOT access, we should disable GOT relaxation with data prefix. gas/ PR gas/23854 * config/tc-i386.c (output_disp): Disable GOT relaxation with data prefix. * testsuite/gas/i386/mixed-mode-reloc32.d: Updated. ld/ PR gas/23854 * testsuite/ld-i386/i386.exp: Run pr23854. * testsuite/ld-x86-64/x86-64.exp: Likewwise. * testsuite/ld-i386/pr23854.d: New file. * testsuite/ld-i386/pr23854.s: Likewwise. * testsuite/ld-i386/pr23854.d: Likewwise. * testsuite/ld-x86-64/pr23854.d: Likewwise. * testsuite/ld-x86-64/pr23854.s: Likewwise. (cherry picked from commit e60f4d3bdac25f02875afe36b7436bc2dfbbb978)