Skip to content

Incorrect detection of Windows executable by gprconfig #152

@LordAro

Description

@LordAro

gprconfig uses the following to determine whether a file is a valid Windows executable

function Is_Windows_Executable (Filename : String) return Boolean is
type Byte is mod 256;
for Byte'Size use 8;
for Byte'Alignment use 1;
type Bytes is array (Positive range <>) of Byte;
Windows_Pattern : constant Bytes := (77, 90, 144, 0);
Fd : constant File_Descriptor := Open_Read (Filename, Binary);
B : Bytes (1 .. 4);
N_Read : Integer;
begin
N_Read := Read (Fd, B'Address, 4);
Close (Fd);
if N_Read < 4 then
return False;
else
if B = Windows_Pattern then
return True;
else
return False;
end if;
end if;
end Is_Windows_Executable;

specifically looking at the first 4 bytes of the file match using Windows_Pattern : constant Bytes := (77, 90, 144, 0);

This is typically works, but it's not actually correct - only MZ / 0x4d5a is required, the 3rd & 4th bytes are actually just e_cblp, or "Bytes on last page of file". It seems typically that's set to 0x90, but not exclusively. I'm not sure anything actually uses it.

However, I've just run into an issue where gprconfig refuses to recognise a compiler that was linked with lld where it's set to 0x78 (apparently the lld linker does actually set it?) (best not ask exactly why I'm doing this)

The correct method of determining a valid binary is to lookup the COFF File header at position 0x3c and then find the machine type - https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#coff-file-header-object-and-image

I implemented this routine in Perl a while back, which may prove of interest.

    my ($path) = @_;
    $path->open( "<:raw" );
    my @bytes = unpack( "C*", $path->read_n_bytes( 4 ) );
    my $arch;
    if( $bytes[ 0 ] == 0x4d && $bytes[ 1 ] == 0x5a )
    {
        # COFF binary (Windows)
        $path->seek_abs( 0x3c );
        my $header_pos = unpack( "L", $path->read_n_bytes( 4 ) );
        $path->seek_abs( $header_pos + 4 );
        my $machine = unpack( "S", $path->read_n_bytes( 2 ) );
        if( $machine == 0x14c ) # IMAGE_FILE_MACHINE_I386
        {
            $arch = 32;
        }
        elsif( $machine == 0x8664 ) # IMAGE_FILE_MACHINE_AMD64
        {
            $arch = 64;
        }
        else
        {
            print "Unknown machine type of COFF binary " . $path->get_absolute_name() . ": $machine\n";
        }
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions