https://sourceware.org/bugzilla/show_bug.cgi?id=32432
Bug ID: 32432
Summary: GAS emitting wrong operand size for some push
instructions in .code16gcc mode
Product: binutils
Version: 2.43.1
Status: UNCONFIRMED
Severity: minor
Priority: P2
Component: gas
Assignee: unassigned at sourceware dot org
Reporter: nikolas.kraetzschmar at gmail dot com
Target Milestone: ---
Assembling in .code16gcc mode using intel assembly syntax fails when the
assembly contains push instructions of the form:
push OFFSET FLAT:0x1234
call func
This produces the following binary output:
Disassembly of section .text:
00000000 <func-0xa>:
0: 66 68 34 12 66 e8 pushd 0xe8661234
6: 00 00 add BYTE PTR [bx+si],al
...
0000000a <func>:
a: 66 c3 retd
It seems to add the 66 prefix as expected but only outputs a 2-byte operand,
whereas a 4-byte operand is required. Consequently, part of the next
instruction, '66 e8 00 00 00 00 calld c <func>', gets misinterpreted as
part of the operand. This corrupts subsequent instructions, potentially making
the entire code invalid.
Why This Matters
----------------
The initial reaction might be to question why someone would use 'push OFFSET
FLAT:*' in 16-bit code or why not explicitly write 'pushd OFFSET FLAT:*', which
does produce the correct binary output. However, the issue arises because 'push
OFFSET FLAT:*' is the form that GCC generates when passing string literals as
function arguments while building with '-m16 -masm=intel'.
Example Code:
void function(const char *str);
void init()
{
function("abc");
}
Output Assembly:
.file "test.c"
.code16gcc
.intel_syntax noprefix
.text
.section .rodata
.LC0:
.string "abc"
.text
.globl init
.type init, @function
init:
.LFB0:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
sub esp, 8
sub esp, 12
push OFFSET FLAT:.LC0
call function
add esp, 16
nop
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
The 'push OFFSET FLAT:.LC0' instruction triggers the bug, making it impossible
to pass string literals to functions when building with '-m16 -masm=intel'.
Potential Fix
-------------
The following patch appears to resolve the problem. However, I lack sufficient
understanding of the binutils/gas internals to determine whether this is the
correct place to address the issue or if it might introduce other unintended
side effects.
commit 39c2dc99cd0a2dae50f49f2698b718d2a49bfb9d
Author: nkraetzschmar <[email protected]>
Date: Fri Dec 6 01:22:24 2024 +0100
fix gas emitting wrong push operand size for intel syntax in .code16gcc
mode
diff --git a/gas/config/tc-i386.c b/gas/config/tc-i386.c
index aeb9b974451..eab43b4438b 100644
--- a/gas/config/tc-i386.c
+++ b/gas/config/tc-i386.c
@@ -8299,6 +8299,8 @@ optimize_imm (void)
break;
case WORD_MNEM_SUFFIX:
mask.bitfield.imm16 = 1;
+ if (current_templates.start->mnem_off == MN_push &&
stackop_size == LONG_MNEM_SUFFIX)
+ mask.bitfield.imm32 = 1;
break;
case BYTE_MNEM_SUFFIX:
mask.bitfield.imm8 = 1;
--
You are receiving this mail because:
You are on the CC list for the bug.