delorie.com/djgpp/bugs/show.cgi   search  
Bug 000339

When Created: 05/29/2001 10:12:07
Against DJGPP version: 2.03
By whom: avillaci@ceibo.fiec.espol.edu.ec
Abstract: AS incorrectly sign-extends constants assembled with instructions with .code16gcc
When experimenting with the .code16 and .code16gcc directives in order to compile
C code in 16-bit real mode, I found that some constants that appeared in the C
code as parameters to a procedure were being sign extended as if by assignment from
'signed short' to 'signed long'. However, the parameters were unsigned longs like
0x8000UL, passed as arguments to a procedure that takes 'dwords', defined as
'typedef unsigned long dword'. Examination of the assembly output showed that the
compiler was generating the correct opcodes with correct instructions (because the
.code16gcc was given with an __asm__ directive, the compiler could not know that
the code would be assembled to an USE16 segment). Examination through DEBUG showed
that the constant was sign extended in the binary opcodes, though not in the assembly
output. This means that, when assembling with the .code16gcc directive, 'as' incorrectly
sign-extends 32-bit constants that fit in a 16-bit word and have bit 15 set (like
0x00008000UL) (that is, the most significant bit is bit 15), at least with
'pushl $constant' , 'movl $constant, r/m32', and 'andl/orl $constant, r/m32'
instructions. The file 'as_bug.s' is a minimal example that reproduces the bug.
The binary output is the following:

66 68 00 80 FF FF   /* assembled from 'pushl $0x8000', but is really 'pushl $0xFFFF8000' */
66 58			/* popl %eax */
66 83 E0 FF		/* assembled from 'andl $0xFFFF, %eax', but is really 'andl $0xFFFFFFFF, %eax' */
66 B8 FF FF FF FF	/* assembled from 'movl $0xFFFF, %eax', but is really 'movl $0xFFFFFFFF, %eax' */
90				/* NOPs for padding */
90
90
90
90
66 68 00 80 FF FF	/* assembled from 'pushl $0xFFFF8000' */
66 58			/* popl %eax */
66 83 E0 FF		/* assembled from 'andl $0xFFFFFFFF, %eax' */
66 B8 FF FF FF FF	/* assembled from 'movl $0xFFFFFFFF, %eax' */
90				/* NOPs for padding */
90
90
90
90
B8 00 4C			/* Normal exit with INT 21h */
CD 21


Constants assembled in section '.data' with '.long' are not affected by .code16gcc, so
a partial workaroud is to store constants as initialized global variables, which are then
accessed from code. However, this does not work when garbage in the high word of a
32-bit register needs to be masked out with, for example, 'andl $65535, %eax'. This
instruction is emitted every time a function returns with a 16-bit value in a 32-bit register.

Output of 'as --version':
-------------------------
GNU assembler 2.9.5
Copyright 1997 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License.  This program has absolutely no warranty.
This assembler was configured for a target of `i386-pc-msdosdjgpp'.

Patches applied to 'as' source:
-------------------------------
none

Machine in use:
---------------
AMD K5-PR133 at 100 MHz, Award BIOS 1996.

Operating system:
-----------------
Microsoft Windows 95 4.00.950a
IE 5 5.00.2314.1003

Compiler used to compile 'as':
------------------------------
gcc 2.9.5

Makefile used to invoke 'as':
-----------------------------
OBJECTS	=as_bug.o
CC		=gcc

as_bug.com: $(OBJECTS) comfile.djl
	ld -o as_bug.com -Tcomfile.djl $(OBJECTS) --oformat binary -M
.s.o:
	$(CC) -c -o $*.o $*.s

Contents of 'comfile.djl':
--------------------------
OUTPUT_FORMAT("coff-go32")
ENTRY(_start)
SECTIONS
{
	.text 0x100 :
	{
		*(.text)
		. = ALIGN(0x10);
	}
	.data . :
	{
		*(.data)
		. = ALIGN(0x10);
	}
	.bss . :
	{
		*(.bss)
		*(COMMON)
		. = ALIGN(0x10);
	}
}

Assembly input file 'as_bug.s' (minimal example that reproduces bug):
----------------------------------------------------------
.code16gcc
.text
.globl _start
_start:
	pushl $0x8000		/* <-- 0x8000 is being sign extended into 0xFFFF8000 */
	popl %eax			/* Restore stack pointer */
	andl $0xFFFF, %eax	/* <-- incorrectly assembled into 'andl $0xFFFFFFFF, %eax' */
	movl $0xFFFF, %eax	/* <-- incorrectly assembled into 'movl $0xFFFFFFFF, %eax' */

	nop				/* Padding included to get 'objdump --disassemble' into synch */
	nop				/* so that opcodes can be checked for equality */
	nop
	nop
	nop

	/* The above code assembles exactly like the one below (use a hex dump or disassembler to check). */
	pushl $0xFFFF8000
	popl %eax
	andl $0xFFFFFFFF, %eax
	movl $0xFFFFFFFF, %eax

	nop
	nop
	nop
	nop
	nop

	movw $0x4c00, %ax	/* Normal exit through INT 21h */
	int $0x21

Note added: 05/30/2001 13:51:15
By whom: eliz@is.elta.co.il
Thius is not the right place to report bugs in Gas.  Please report
this to the address printed by "as --help".

I'm closing this report.

Closed on 05/30/2001 13:52:01: Not a DJGPP bug
By whom: eliz@is.elta.co.il



  webmaster     delorie software   privacy  
  Copyright © 2010   by DJ Delorie     Updated Jul 2010