Bug 1623218 - GCC's Strip function fails to remove 10k from the executable.
Summary: GCC's Strip function fails to remove 10k from the executable.
Keywords:
Status: CLOSED WORKSFORME
Alias: None
Product: Fedora
Classification: Fedora
Component: gcc
Version: 29
Hardware: x86_64
OS: Linux
unspecified
medium
Target Milestone: ---
Assignee: Nick Clifton
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2018-08-28 18:59 UTC by Leslie Satenstein
Modified: 2019-10-06 16:57 UTC (History)
10 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2019-10-06 16:57:56 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
fstabxref A program to format the /etc/fstab (34.41 KB, application/octet-stream)
2018-09-11 14:21 UTC, Leslie Satenstein
no flags Details
xstabxref the stripped version of fstabxref based on the 8.1 compiler (34.41 KB, application/x-executable)
2018-09-11 14:23 UTC, Leslie Satenstein
no flags Details
with the 8.2 C compiler output (46.44 KB, application/octet-stream)
2018-09-11 14:25 UTC, Leslie Satenstein
no flags Details
stripped version using the 8.2 c compiler (39.64 KB, application/x-executable)
2018-09-11 14:27 UTC, Leslie Satenstein
no flags Details
example of program output of a processed /etc/fstab (1.46 KB, text/plain)
2018-09-11 14:31 UTC, Leslie Satenstein
no flags Details

Description Leslie Satenstein 2018-08-28 18:59:28 UTC
Description of problem:

Fedora 28 GCC's C compiler 8.1.1 generates 
41680 Aug 28 14:51 xfstabxref
Running strip for xfstabxref
35280 Aug 28 14:52 xfstabxref

However
Running strip against gcc 8.2.x for Fedora 29
yields same xfstabxref size but
strip size is 45k in size.  
I typically run strip against all executables and with F29's gcc compiler. I am having 10k extra space used by executable.

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

8.2.1 gcc and related strip executable.

How reproducible:


Steps to Reproduce:
1.xfstabxref : xfstabxref.c  $(LIB) dictionary.h       #Makefile
        ${CC} ${CFLAGS}  $< $(LIB) -o $@ 

2.  strip:          #shows before/after
        @for var in ${PROGS} ; \
        do \
                ls -l $${var} ; \
                /usr/bin/strip $${var} ; \
                ls -l $${var} ; \
                /usr/bin/echo " " ; \
        done ;

3.

Actual results:


Expected results:


Additional info:

Comment 1 Leslie Satenstein 2018-08-28 19:01:13 UTC
/usr/bin/strip

Comment 2 Jonathan Wakely 2018-08-29 09:25:27 UTC
(In reply to Leslie Satenstein from comment #0)
> Version-Release number of selected component (if applicable):
> 
> 8.2.1 gcc and related strip executable.

There is no "related strip executable" because it's not part of gcc. Please provide the proper version info, e.g. by running:

rpm -qf /usr/bin/strip /usr/bin/gcc

Comment 3 Jakub Jelinek 2018-08-29 09:40:49 UTC
The version info isn't the only thing totally missing from this, there are no details what exactly you are compiling and whether the problem is in code growth from gcc (I find that quite unlikely, as it is only a very minor difference in between, just 20 days of gcc bugfixing), or if the difference is in the linker between f28 and f29.
If it was built using rpm, my first guess would be the annobin plugin and sections it creates, otherwise I wonder if the new -z separate-code isn't the default in the linker.

Guess best information would be run readelf -Wa on the f28 and f29 unstripped and stripped binaries and attach those here, then it can be easily compared what grew how much.

Comment 4 Leslie Satenstein 2018-09-01 12:38:08 UTC
For some reason, I did not read your response until I started to look at my active bug report list. 

My code is pure command line C, with malloc/free, directory reads, and link following.

Code can be attached if desired.

Comment 5 Leslie Satenstein 2018-09-01 12:46:03 UTC
Recently I am unable to install F29 Gnome beta. It is not F29 Anaconda or DNF code that prevents the installation, it is one or more rpms that anaconda pulls in that crash dnf which in turn crashes anaconda.

Follow up to strip when I can do it.

Currently /usr/bin/strip is from  binutils-2.29.1-23.fc28.x86_64

Will update with more info when I can clean install F29.

Please redirect to binutils.

Comment 6 Nick Clifton 2018-09-03 10:53:54 UTC
Hi Leslie,

  Please can you provide the unstripped executable for testing ?

  I strongly suspect that the reason will turn out to be a new
  feature of the linker which is putting code and read-only data
  into different segments in the executable.  This makes the program
  safer - because the code segment can be marked as executable,
  whereas the read-only data segment can be marked as non-executable -
  but it does lead to an increase in the size of the program, because
  the segments need to be page aligned.

  You could test this for yourself by adding "-wl,-z,-noseparate-code" 
  to your command line and see if this results in a smaller binary.

Cheers
  Nick

Comment 7 Leslie Satenstein 2018-09-11 14:21:34 UTC
Created attachment 1482376 [details]
fstabxref      A program to format the /etc/fstab

The compiled executable created with 8.1 compiler

Comment 8 Leslie Satenstein 2018-09-11 14:23:36 UTC
Created attachment 1482377 [details]
xstabxref     the stripped version of fstabxref based on the 8.1 compiler

the stripped version of fstabxref based on the 8.1 compiler

Comment 9 Leslie Satenstein 2018-09-11 14:25:52 UTC
Created attachment 1482378 [details]
with the 8.2 C compiler output

Comment 10 Leslie Satenstein 2018-09-11 14:27:43 UTC
Created attachment 1482379 [details]
stripped version using the 8.2 c compiler

CC=gcc
CFLAGS=  -O3  -Wall  -Wextra -Fpic

Comment 11 Leslie Satenstein 2018-09-11 14:31:31 UTC
Created attachment 1482381 [details]
example of program output of a processed  /etc/fstab

Comment 12 Nick Clifton 2018-09-13 13:58:08 UTC
Hi Leslie,

  This is exactly as I predicted.  The Fedora 28 binary (fstabxref) only has
  two loadable segments in it, one of which contains both the code and the
  read-only data, and one of which contains the writeable data.  The segment
  containing the code/read-only data has the R (read) and E (execute)
  permission flags, which means that in theory, if there are sequences in the 
  read-only data that looked like instructions, an attacker might be able to
  make use of them.

  The Fedora 29 binary (fstabxref1) has four loadable segments, one 
  containing relocations, one containing only code, one containing read-only 
  data, and one containing writeable data.  The segment containing the 
  read-only data just has the R (read) permission flag, so it cannot be 
  executed as if it were code.

  % readelf --wide --segments fstavxref*

  File: fstabxref
  [...]
  Program Headers:
    Type  Offset   VirtAddr     PhysAddr     FileSiz  MemSiz   Flg Align
  [...]
    LOAD  0x000000 0x0000400000 0x0000400000 0x006b00 0x006b00 R E 0x200000
    LOAD  0x006e10 0x0000606e10 0x0000606e10 0x0013b1 0x0045a8 RW  0x200000
 [...]
 Section to Segment mapping:
   02     [...] .text .fini .rodata [...]
   03     [...] .data [...]
  [...] 

  File: fstabxref1
  [...]
  Program Headers:
    Type  Offset   VirtAddr     PhysAddr     FileSiz  MemSiz   Flg Align
    LOAD  0x000000 0x0000400000 0x0000400000 0x000e18 0x000e18 R   0x1000
    LOAD  0x001000 0x0000401000 0x0000401000 0x0039f5 0x0039f5 R E 0x1000
    LOAD  0x005000 0x0000405000 0x0000405000 0x002290 0x002290 R   0x1000
    LOAD  0x007e10 0x0000408e10 0x0000408e10 0x0013b1 0x0045a8 RW  0x1000
  [...]
  Section to Segment mapping:
   02     [...] .rela.dyn .rela.plt 
   03     [...] .text [...]
   04     .rodata [...]
   05     [...] .data [...]
  [...]


  My advice would be to either accept the increase in size - because it 
  increases the security of your programs - or else to link them with the
  -Wl,-z,noseparate-code command line option.  This will give you back the
  binary sizes you expect, at the cost of some security hardening of your
  programs.

Cheers
  Nick

Comment 13 Jakub Jelinek 2018-09-13 14:13:11 UTC
Nick, do we really need 4 PT_LOAD segments rather than just 3 for -z separate-code?
I mean, can't we simply use a different linker script for -z separate-code, where sections will be reordered such that all the ones that need to be read-only non-executable go first (first PT_LOAD), then the read-only/executable ones (second PT_LOAD) and finally like before the read-write/non-executable ones including relro ones at the start?

E.g. looking at bash in f30:
  LOAD           0x000000 0x0000000000000000 0x0000000000000000 0x02bf60 0x02bf60 R   0x1000
  LOAD           0x02c000 0x000000000002c000 0x000000000002c000 0x0a74b5 0x0a74b5 R E 0x1000
  LOAD           0x0d4000 0x00000000000d4000 0x00000000000d4000 0x033ff0 0x033ff0 R   0x1000
  LOAD           0x108d50 0x0000000000109d50 0x0000000000109d50 0x00b814 0x0153d8 RW  0x1000

   02     .interp .note.gnu.property .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt 
   03     .init .plt .plt.sec .text .fini 
   04     .rodata .eh_frame_hdr .eh_frame 
   05     .init_array .fini_array .data.rel.ro .dynamic .got .data .bss 

Can't we move .rodata, .eh_frame_hdr and .eh_frame sections after .rela.plt, to make it:
   02     .interp .note.gnu.property .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .rodata .eh_frame_hdr .eh_frame 
   03     .init .plt .plt.sec .text .fini 
   04     .init_array .fini_array .data.rel.ro .dynamic .got .data .bss 
elf.sc already has ${SEPARATE_CODE} conditionals.
In elf.sc perhaps easier made by moving the .init ... ${RELOCATING+PROVIDE (${ETEXT_NAME} = .);} stuff if SEPARATE_CODE from the current location to after all the read-only sections.

Comment 14 Nick Clifton 2018-09-18 16:28:50 UTC
Hi Jakub,

> Do we really need 4 PT_LOAD segments

  Probably not, but I really do not want to rock the boat here.  Changing the
  default linker script is bound to cause problems somewhere, even if I cannot
  say exactly where.  If a package maintainer is really interested in reducing
  the size of their binaries, as Leslie clearly is, then they are free to copy
  the default script, modify it as they wish, and then use that for their
  linking.  But I would much rather that this kind of thing was the exception
  to the rule, rather than the default.

  Basically I do not want to break Fedora (again!)

Cheers
  Nick

Comment 15 Jakub Jelinek 2018-09-18 16:32:54 UTC
Sure, this is something that shouldn't be done as a Fedora change, but upstream, get tested there and put into F30 or whenever we grab the binutils that has it.

I just don't have spare cycles for binutils development myself (though if needed, I could file an upstream PR).

Comment 16 Leslie Satenstein 2018-09-24 21:50:32 UTC
I can wait.  I have ample diskspace remaining on my 128k SSD as I made room therein by moving /var to a spinning HD.

I strip all the stuff I write and to keep SSD space use to a minimum, I do likewise where I can with Fedora distributed software.

I will go with the "flow" in that if the status is quo, then it is what it is,
if there is a merge or relocatable RO with static RO, I can wait for that outcome.

What is the status of this bug report? Pending, Closed, Won't fix ?

Comment 17 Nick Clifton 2018-09-27 15:34:02 UTC
I would like to set CLOSED/WONTFIX, if that is OK with you.

Comment 18 Leslie Satenstein 2018-10-04 01:59:49 UTC
YES, But instead of wont fix, can you check with gcc maintainers to see if they can get the parameters recognized.

By the way, The above program is gcc free license. I wrote it,
it is very useful if you have multiple /etc/fstab files scattered and the only reference you have is 

UUID=xxx
or
other

Comment 19 Leslie Satenstein 2018-10-04 02:01:15 UTC
The recognized parms was to make the linker more efficient.

the above programs are free to use and distribute.

Comment 20 Leslie Satenstein 2018-10-18 13:50:50 UTC
1623218  followup

Same executable, when compiled with Clang, produces a 4.5k smaller executable.

Comment 21 Leslie Satenstein 2019-10-06 16:57:56 UTC
GCC version 9 and strip coexist nicely,

It now works for me.


Note You need to log in before you can comment on or make changes to this bug.