[Bug gas/29494] New: Trailing jump table leads to "Error: unaligned opcodes detected in executable segment" on ARM thumb

2022-08-15 Thread gus at projectgus dot com
https://sourceware.org/bugzilla/show_bug.cgi?id=29494

Bug ID: 29494
   Summary: Trailing jump table leads to "Error: unaligned opcodes
detected in executable segment" on ARM thumb
   Product: binutils
   Version: 2.39
Status: UNCONFIRMED
  Severity: normal
  Priority: P2
 Component: gas
  Assignee: unassigned at sourceware dot org
  Reporter: gus at projectgus dot com
  Target Milestone: ---

Created attachment 14281
  --> https://sourceware.org/bugzilla/attachment.cgi?id=14281&action=edit
ltrans assembler listing that exhibits the problem

When LTO is enabled then it's possible for gcc to generate a jump table where
the table data is the last thing in its executable section. (i.e. all of the
jump table entries point to offsets earlier in the section, and no other
instructions appear after it.)

On ARM thumb (min 2 byte instructions), if a jump table with single byte
entries has an odd number of entries then the section ends at an odd numbered
offset.

If also generating DWARF debug info, it appears the check in gas/dwarf2db.c
scale_addr_delta() will then fail with "unaligned opcodes detected in
executable segment".

However, the assembly listing is otherwise correct.

I ran across this in the MicroPython project, with a code snippet in
objint_mpz.c:315 as follows:

...
switch (op) {
case MP_BINARY_OP_LESS:
return mp_obj_new_bool(cmp < 0);
case MP_BINARY_OP_MORE:
return mp_obj_new_bool(cmp > 0);
case MP_BINARY_OP_LESS_EQUAL:
return mp_obj_new_bool(cmp <= 0);
case MP_BINARY_OP_MORE_EQUAL:
return mp_obj_new_bool(cmp >= 0);
case MP_BINARY_OP_EQUAL:
return mp_obj_new_bool(cmp == 0);

default:
return MP_OBJ_NULL; // op not supported
}
}


With -Os and no LTO, gcc 12.1 generates a jump table, and emits more assembly
after it:

...
.loc 1 315 9 view .LVU1204
bl  __gnu_thumb1_case_uqi
.L105:
.byte   (.L109-.L105)/2
.byte   (.L108-.L105)/2
.byte   (.L107-.L105)/2
.byte   (.L106-.L105)/2
.byte   (.L104-.L105)/2
.p2align 1
.L109:
.loc 1 317 17 is_stmt 1 view .LVU1205
.LVL211:
.LBB240:
.LBI237:
.loc 3 781 24 view .LVU1206
.LBB239:
.loc 3 782 5 view .LVU1207
.loc 3 782 30 is_stmt 0 view .LVU1208
cmp r3, #0
blt .LCB2415
b   .L70@long jump
...

With LTO enabled, the local translations further optimise and rearrange until
the jump table appears at the end of the executable listing for the enclosing
function and section:

...
.LBB303:
.loc 2 315 9 is_stmt 1 view .LVU1105
ldr r2, [sp, #16]
cmp r2, #4
bhi .L13
movsr0, r2
bl  __gnu_thumb1_case_sqi
.L111:
.byte   (.L109-.L111)/2
.byte   (.L108-.L111)/2
.byte   (.L118-.L111)/2
.byte   (.L106-.L111)/2
.byte   (.L104-.L111)/2
.LBE303:
.cfi_endproc
.LFE0:
.size   mp_obj_int_binary_op, .-mp_obj_int_binary_op
.text
.Letext0:
.file 10 ""
.section.debug_info,"",%progbits
...

As a result, the executable section ends with an odd length, and linking fails
due to the assembler DWARF generation error:

build-NUCLEO_F091RC/firmware.elf.ltrans1932.ltrans.s: Assembler messages:
build-NUCLEO_F091RC/firmware.elf.ltrans1932.ltrans.s: Error: unaligned opcodes
detected in executable segment
make[1]: *** [/tmp/ccfzQYxO.mk:3866:
build-NUCLEO_F091RC/firmware.elf.ltrans1932.ltrans.o] Error 1

Manually running "arm-none-eabi-as firmware.elf.ltrans1932.ltrans.s" produces
the same error, and inserting a padding ".byte 0" in the listing after the jump
table will fix the error.

It might be the case that this is gcc's fault for generating an executable
section with an odd length, but given the table is the last thing in the
section it seems reasonable not to pad it.

Indeed, if "-g" isn't passed to the compiler then the assembler produces valid
binary code and everything works, it's only DWARF generation which fails.

I am wondering if a suitable patch would be to ignore this check if there are
no additional opcodes following the odd offset, i.e. ignore the failure
condition if it's positioned at the end of a section. If so, I'm happy to try
and write that patch. However, I'm not very familiar with gas or DWARF so I'm
guessing it might be much more complex than this!

Looks like I can only attach one file, so rather than an archive I've attached
the ltrans assembler listing which exhibits the issue. If it's helpful then I
can provide more example files, or write a simpler assembler listing to
reproduce.

Thanks in advance for any insights!

-- 
You are receiving this mail because:
You are on the CC list for the bug.


[Bug gas/29494] Trailing jump table leads to "Error: unaligned opcodes detected in executable segment" on ARM thumb

2022-08-23 Thread gus at projectgus dot com
https://sourceware.org/bugzilla/show_bug.cgi?id=29494

--- Comment #5 from Angus Gratton  ---
Thanks heaps Nick for the patch. It's going to be a couple of days until I can
test this, sorry. But I will definitely do so!

-- 
You are receiving this mail because:
You are on the CC list for the bug.


[Bug gas/29494] Trailing jump table leads to "Error: unaligned opcodes detected in executable segment" on ARM thumb

2022-08-27 Thread gus at projectgus dot com
https://sourceware.org/bugzilla/show_bug.cgi?id=29494

--- Comment #6 from Angus Gratton  ---
Thanks heaps for being patient and for looking into this so quickly.

I just tested Alan's "Simpler patch" and it seems to solve the issue entirely.

-- 
You are receiving this mail because:
You are on the CC list for the bug.