From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 35730 invoked by alias); 5 Mar 2020 13:55:51 -0000 Mailing-List: contact binutils-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: binutils-owner@sourceware.org Received: (qmail 35713 invoked by uid 89); 5 Mar 2020 13:55:51 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.1 spammy=NEXT, H*Ad:U*amodra, sk:assign_, algn X-HELO: smtp.eu.adacore.com Received: from mel.act-europe.fr (HELO smtp.eu.adacore.com) (194.98.77.210) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 05 Mar 2020 13:55:48 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id 344DD81A12; Thu, 5 Mar 2020 14:55:46 +0100 (CET) Received: from smtp.eu.adacore.com ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id pNe7cXa014dd; Thu, 5 Mar 2020 14:55:46 +0100 (CET) Received: from [10.10.126.96] (wifi-guest-96.act-europe.fr [10.10.126.96]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.eu.adacore.com (Postfix) with ESMTPSA id 0AB3381397; Thu, 5 Mar 2020 14:55:46 +0100 (CET) From: KONRAD Frederic Subject: ld: output section alignment and empty section. To: binutils@sourceware.org Cc: Alan Modra Message-ID: Date: Thu, 05 Mar 2020 13:55:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Thunderbird/68.5.0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit X-IsSubscribed: yes X-SW-Source: 2020-03/txt/msg00119.txt Hi, I just figured out that the following linker script hunk: . = ALIGN(0x4); .rodata : { . = ALIGN(0x4); } is creating an empty .rodata output section while I was expecting it not to be emited. This is because we flag ". = ALIGN(xxx)" as SEC_KEEP in exp_fold_tree_1. Dropping that for ". = ALIGN(constant)" seems to fix the behavior: diff --git a/ld/ldexp.c b/ld/ldexp.c index 23ee5c5..60a5d67 100644 --- a/ld/ldexp.c +++ b/ld/ldexp.c @@ -962,30 +962,43 @@ is_dot_ne_0 (const etree_type *tree) } /* Return true if TREE is ". = . + 0" or ". = . + sym" where sym is an absolute constant with value 0 defined in a linker script. */ static bfd_boolean is_dot_plus_0 (const etree_type *tree) { return (tree->type.node_class == etree_binary && tree->type.node_code == '+' && is_dot (tree->binary.lhs) && (is_value (tree->binary.rhs, 0) || is_sym_value (tree->binary.rhs, 0))); } +/* Return true if TREE is "ALIGN (constant)". */ +static bfd_boolean +is_align_constant (const etree_type *tree) +{ + if (tree->type.node_class == etree_unary + && tree->type.node_code == ALIGN_K) + { + tree = tree->unary.child; + return tree->type.node_class == etree_value; + } + return FALSE; +} + /* Return true if TREE is "ALIGN (. != 0 ? some_expression : 1)". */ static bfd_boolean is_align_conditional (const etree_type *tree) { if (tree->type.node_class == etree_unary && tree->type.node_code == ALIGN_K) { tree = tree->unary.child; return (tree->type.node_class == etree_trinary && is_dot_ne_0 (tree->trinary.cond) && is_value (tree->trinary.rhs, 1)); } return FALSE; } @@ -1054,30 +1067,31 @@ exp_fold_tree_1 (etree_type *tree) exp_fold_tree_1 (tree->assign.src); expld.assigning_to_dot = FALSE; /* If we are assigning to dot inside an output section arrange to keep the section, except for certain expressions that evaluate to zero. We ignore . = 0, . = . + 0, and . = ALIGN (. != 0 ? expr : 1). We can't ignore all expressions that evaluate to zero because an otherwise empty section might have padding added by an alignment expression that changes with relaxation. Such a section might have zero size before relaxation and so be stripped incorrectly. */ if (expld.phase == lang_mark_phase_enum && expld.section != bfd_abs_section_ptr && expld.section != bfd_und_section_ptr + && !is_align_constant (tree->assign.src) && !(expld.result.valid_p && expld.result.value == 0 && (is_value (tree->assign.src, 0) || is_sym_value (tree->assign.src, 0) || is_dot_plus_0 (tree->assign.src) || is_align_conditional (tree->assign.src)))) expld.section->flags |= SEC_KEEP; if (!expld.result.valid_p || expld.section == bfd_und_section_ptr) { if (expld.phase != lang_mark_phase_enum) einfo (_("%F%P:%pS invalid assignment to" " location counter\n"), tree); } -------------------------------------------------- Only the comment above which comes from: commit e0a3af227ee0602ae69320fd6f931c363f14975b Author: Alan Modra Date: Thu Aug 6 15:56:34 2015 +0930 Revert ALIGN changes Reverts a2c59f28 and e474ab13. Since the unary form of ALIGN only references "dot" implicitly, there isn't really a strong argument for making ALIGN use a relative value when inside an output section. * ldexp.c (align_dot_val): Delete. (fold_unary ): Revert 2015-07-10 change. (is_align_conditional): Revert 2015-07-20 change. (exp_fold_tree_1): Likewise, but keep expanded comment. * scripttempl/elf.sc (.ldata, .bss): Revert 2015-07-20 change. * ld.texinfo (): Correct description. kinds of worry me: /* If we are assigning to dot inside an output section arrange to keep the section, except for certain expressions that evaluate to zero. We ignore . = 0, . = . + 0, and . = ALIGN (. != 0 ? expr : 1). We can't ignore all expressions that evaluate to zero because an otherwise empty section might have padding added by an alignment expression that changes with relaxation. Such a section might have zero size before relaxation and so be stripped incorrectly. */ Is that because strip_excluded_output_sections happens before the relaxation? Could that be a problem in the case of a constant alignment? The reason why I'm trying to remove those empty sections is that there are some cases where later in the link process it confuses the program header, ie in my case: .rodata is considered as overlapping with .srodata so it creates two PT_LOAD segments in the Program Header: architecture: riscv:rv64, flags 0x00000112: EXEC_P, HAS_SYMS, D_PAGED start address 0x0000000080000000 Program Header: LOAD off 0x0000000000001000 vaddr 0x0000000080000000 paddr\ 0x0000000080000000 align 2**12 filesz 0x00000000000002b4 memsz 0x00000000000002b4 flags r-x LOAD off 0x00000000000022b0 vaddr 0x00000000800002b0 paddr\ 0x00000000800002b0 align 2**12 filesz 0x0000000000000034 memsz 0x0000000000001040 flags rw- Sections: Idx Name Size VMA LMA File off Algn 0 .host_target_interface 00000010 0000000000000000 0000000000000000 000022e4 2**0 CONTENTS, READONLY 1 .text 000002b0 0000000080000000 0000000080000000 00001000 2**1 CONTENTS, ALLOC, LOAD, READONLY, CODE 2 .rodata 00000000 00000000800002b0 00000000800002b0 000022b0 2**0 ALLOC 3 .srodata 00000004 00000000800002b0 00000000800002b0 000012b0 2**3 CONTENTS, ALLOC, LOAD, READONLY, DATA 4 .data 00000000 00000000800002b4 00000000800002b4 000022b4 2**0 CONTENTS, ALLOC, LOAD, DATA 5 .sdata 00000028 00000000800002b8 00000000800002b8 000022b8 2**3 CONTENTS, ALLOC, LOAD, DATA 6 .sdata2 00000004 00000000800002e0 00000000800002e0 000022e0 2**0 CONTENTS, ALLOC, LOAD, READONLY, DATA And then when loading this file .srodata get's overwritten by .rodata.. An other possible fix would be to disregard empty sections in _bfd_elf_map_sections_to_segments: diff --git a/bfd/elf.c b/bfd/elf.c index fcd84d2..c37aa23 100644 --- a/bfd/elf.c +++ b/bfd/elf.c @@ -4844,11 +4844,13 @@ _bfd_elf_map_sections_to_segments (bfd *abfd, struct bfd_link_info *info) segment. */ new_segment = TRUE; } - else if (hdr->lma < last_hdr->lma + last_size + else if ((hdr->lma < last_hdr->lma + last_size || last_hdr->lma + last_size < last_hdr->lma) + && hdr->size) { /* If this section has a load address that makes it overlap - the previous section, then we need a new segment. */ + the previous section, and this section is not empty then we + need a new segment. */ new_segment = TRUE; } else if ((abfd->flags & D_PAGED) != 0 @@ -5784,7 +5786,8 @@ assign_file_positions_for_load_sections (bfd *abfd, if (adjust != 0 && (s_start < p_end - || p_end < p_start)) + || p_end < p_start) + && sec->size) { _bfd_error_handler /* xgettext:c-format */ What do you think? Best Regards, Fred