Bug 1807308

Summary: objcopy can not embed data to shared library, and --set-section-flags donot work with "share" flag.
Product: Red Hat Enterprise Linux 8 Reporter: Kirby Zhou <kirbyzhou>
Component: binutilsAssignee: Nick Clifton <nickc>
binutils sub component: system-version QA Contact: Miloš Prchlík <mprchlik>
Status: CLOSED ERRATA Docs Contact:
Severity: unspecified    
Priority: unspecified CC: fweimer, law, mcermak, mprchlik, ohudlick, sipoyare, tschelle
Version: 8.1Keywords: Bugfix, Reopened, Triaged
Target Milestone: rc   
Target Release: 8.0   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: binutils-2.30-74.el8 Doc Type: No Doc Update
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2020-11-04 01:41:45 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Kirby Zhou 2020-02-26 04:28:59 UTC
Description of problem:

objcopy can not embed data to shared library.
and --set-section-flags donot work with "share" flag.

Version-Release number of selected component (if applicable):

binutils-2.30-58.el8.0.1.x86_64
gcc-8.3.1-4.5.el8.x86_64

How reproducible:

100%

Steps to Reproduce:
1.
]# cat > test_dicmap.cpp <<__EOF
#include <stdio.h>
#include <stdint.h>

extern "C" {
extern const uint8_t _binary_dicmap_bin_start[];
extern const uint8_t _binary_dicmap_bin_end[];
extern const void* _binary_dicmap_bin_size;
}

int main()
{
	size_t size = (size_t)&_binary_dicmap_bin_size;
	printf("start=%p, end=%p\nend-start=%zd, size=%zd\n", 
		_binary_dicmap_bin_start, 
		_binary_dicmap_bin_end,
		_binary_dicmap_bin_end - _binary_dicmap_bin_start,
		size);
	printf("data[0..8]=%02x %02x %02x %02x %02x %02x %02x %02x\n", 
			_binary_dicmap_bin_start[0], _binary_dicmap_bin_start[1], 
			_binary_dicmap_bin_start[2], _binary_dicmap_bin_start[3],
			_binary_dicmap_bin_start[4], _binary_dicmap_bin_start[5], 
			_binary_dicmap_bin_start[6], _binary_dicmap_bin_start[7]);
}
__EOF
]# echo helloworld > dicmap.bin

2.
]# objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o && g++ -o libxxx.so dicmap.o -shared  &&  g++ -L. -lxxx  test_dicmap.cpp 

3.
]# LD_LIBRARY_PATH=. ./a.out

4. try to add "share" flags to .data section

]# objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o --set-section-flags .data=share
objcopy: BFD version 2.30-58.el8.0.1 internal error, aborting at elf.c:8878 in _bfd_elf_set_section_contents

objcopy: Please report this bug.

Actual results:

/usr/bin/ld: warning: type and size of dynamic symbol `_binary_dicmap_bin_end' are not defined
/usr/bin/ld: warning: type and size of dynamic symbol `_binary_dicmap_bin_size' are not defined
/usr/bin/ld: warning: type and size of dynamic symbol `_binary_dicmap_bin_start' are not defined

start=0x601024, end=0x601024
end-start=0, size=6295588
data[0..8]=00 00 00 00 00 00 00 00


Expected results:

end-start=11, size=11
data[0..8]=68 65 6c 6c 6f 77 6f 72

Additional info:

Directly embed data into a.out is OK:

]# objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o && g++ -o libxxx.so dicmap.o -shared && g++ test_dicmap.cpp dicmap.o
]# ./a.out

objcopy --set-section-flags .data=share crash

objcopy: BFD version 2.30-58.el8.0.1 internal error, aborting at elf.c:8878 in _bfd_elf_set_section_contents

objcopy: Please report this bug.

binutils-2.27-41.base.el7_7.1.x86_64 of RHEL7 have the same problem.

Comment 1 Kirby Zhou 2020-02-27 06:55:31 UTC
Maybe there is some bug in ld or ld-linux.so or gcc?
I write a asm file to simulate the objcopy, but still failed.

]$ cat dicmap.asm 
    .section .rodata
    .global _binary_dicmap_bin_start
    .type   _binary_dicmap_bin_start, @object
    .align  8
_binary_dicmap_bin_start:
    #.incbin "dicmap.bin"
    .string "helloworld"
    .global _binary_dicmap_bin_end
    .type   _binary_dicmap_bin_end, @object
_binary_dicmap_bin_end:
    .global _binary_dicmap_bin_size
    .type   _binary_dicmap_bin_size, @object
    .align  8
    .offset _binary_dicmap_bin_end - _binary_dicmap_bin_start
_binary_dicmap_bin_size:

Actual (dynamic link)
]$ as -k --64  dicmap.asm  -o dicmap.o && gcc -shared -o libxxx.so dicmap.o && g++ -L. -lxxx test_dicmap.cpp && ./a.out
start=0x60103c, end=0x60103c
end-start=0, size=6295612
data[0..8]=00 00 00 00 00 00 00 00
a.out: test_dicmap.cpp:27: int main(): Assertion `_binary_dicmap_bin_end - _binary_dicmap_bin_start == data_size' failed.
Aborted

Expected (use static link to simulate)
]$ as -k --64  dicmap.asm  -o dicmap.o && g++ dicmap.o test_dicmap.cpp && ./a.out
start=0x400730, end=0x40073b
end-start=11, size=11
data[0..8]=68 65 6c 6c 6f 77 6f 72

Comment 2 Kirby Zhou 2020-02-27 07:26:30 UTC
More information:
If you take gdb to watch the symbol, It will give a different value than the program sees.

]$ gdb test_dicmap 
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-115.el7
(gdb) b main
Breakpoint 1 at 0x400690: file test_dicmap.cpp, line 15.
(gdb) r
Breakpoint 1, main () at test_dicmap.cpp:15
(gdb) p _binary_dicmap_bin_start 
$1 = 0x7ffff7bd96d8 "helloworld"
(gdb) p _binary_dicmap_bin_end
$2 = 0x7ffff7bd96e3 ""
(gdb) p _binary_dicmap_bin_end-_binary_dicmap_bin_start 
$3 = 11
(gdb) c
Continuing.
start=0x60103c, end=0x60103c
end-start=0, size=6295612
data[0..8]=00 00 00 00 00 00 00 00
lt-test_dicmap: test_dicmap.cpp:27: int main(): Assertion `_binary_dicmap_bin_end - _binary_dicmap_bin_start == data_size' failed.

Comment 3 Kirby Zhou 2020-02-27 10:09:40 UTC
Workaround:

Compile test_dicmap.cpp with "-fPIC", which is an uncommon usage for compiling main programs.

]$ as -k --64  dicmap.asm  -o dicmap.o && gcc -shared -o libxxx.so dicmap.o && g++ -fPIC -L. -lxxx test_dicmap.cpp && ./a.out
start=0x7ff3fd9826b8, end=0x7ff3fd9826c3
end-start=11, size=11
data[0..8]=68 65 6c 6c 6f 77 6f 72

Comment 4 Nick Clifton 2020-03-03 15:10:44 UTC
Hi Kirby,

  It is intentional that you cannot use objcopy to convert a static binary into a shared binary.

  It needs a lot more work, than just changing a flag in a section header.  The entire binary
  needs to be recompiled with the correct command line options if you want to make it a shared
  binary.  The workaround you mention is just this - compiling for a shared executable instead
  of a static one.

Comment 5 Nick Clifton 2020-03-06 10:15:10 UTC
Reopening after further discussions with the reporter.

There are three issues here.  The first is that the "share" section flag cannot be used to make a shared ELF section.

The second is that the objcopy program should not allow the user to try this, and the documentation should inform the user that this is not allowed.

The third is that the BFD library should not call abort() when the situation does arise, but instead issue an error message and return a failure result.

A patch has been committed upstream to fix the second and third problems:
https://www.sourceware.org/ml/binutils/2020-03/msg00143.html

Comment 6 Nick Clifton 2020-04-15 14:21:14 UTC
Fixed in inutils-2.30-74.el8

Comment 9 Miloš Prchlík 2020-09-03 08:11:11 UTC
Verified with binutils-2.30-77.el8. After Nick's comment #4 and comment #5, this is the final result:

$ objcopy -B i386 -I binary -O elf64-x86-64 dicmap.bin dicmap.o --set-section-flags .data=share
objcopy: dicmap.o[.data]: Note - dropping 'share' flag as output format is not COFF

Comment 12 errata-xmlrpc 2020-11-04 01:41:45 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory (Low: binutils security update), and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

https://access.redhat.com/errata/RHSA-2020:4465