From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x62f.google.com (mail-ej1-x62f.google.com [IPv6:2a00:1450:4864:20::62f]) by sourceware.org (Postfix) with ESMTPS id 65A0A3858D33 for ; Mon, 26 Dec 2022 10:48:02 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 65A0A3858D33 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-ej1-x62f.google.com with SMTP id bj12so25361328ejb.13 for ; Mon, 26 Dec 2022 02:48:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=user-agent:in-reply-to:content-transfer-encoding :content-disposition:mime-version:references:message-id:subject:to :from:date:from:to:cc:subject:date:message-id:reply-to; bh=Rtb3hUUlaTEMEET4LUxYo23MElmwSk/wr5Vf2ltR0PY=; b=SCYzBjm7OZ3ibwyGdjRamTapMbX4VTI8d+W2sfmwBwxau43wZcbKAlx7OGmrOLc8uo GjJIB/bQjzAsTVAAjqOk8Xo7sBW40vkBZUw+TpYFzk42rtgKi6XpkTwkrBmNw4x/t/Du X74txDVqx/9pSSZRK0jHVgzDb7tPutDjz85c+O7bkAvc117MIUJiEpOinQNgCo5AVBxz jhPeIydw95ZiFEaXcs4LhJsJvgT4wuYVtGE7Yv07m1iWDAr5RHRMKHi9w7CpEv+aN1A3 dUJOC9K4DF0rpkHBqMYIwR1eC4In4SaI+vB2MyeAi1oH8fAbpH67K8gXmi9Z3G7siWVW PT5A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=user-agent:in-reply-to:content-transfer-encoding :content-disposition:mime-version:references:message-id:subject:to :from:date:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=Rtb3hUUlaTEMEET4LUxYo23MElmwSk/wr5Vf2ltR0PY=; b=bmzUdLeAQilFtpm4Wxh+bu09FR2Z05Rsmd1ooD000MjK8/ewY73MibpFnpujwqKy1P D2cMBTgtpw2c1Ims2F5klwRjyk9g1fNuGUuZQgpr8NASvmZmf9TYbMWpf4dsJuam7Pni zDADSSFPOpZzi/Ty06lXd1+2p9h1w64Sm8LRWMNULkjsto2q8jzyFeP2LUdPoI/lDeGN jnJyjAVm4lRyn6K6tgo4YYO6PR2b+whsMM4tVwQwk5qbLze3WS7W34Gq9ZSaYLwDZ8o+ F1DyPNkblf4b5WAdySH1ACBbP6aOdTBkrhxpAQ4YqgsMNfIHesZvjOsuK0Ql4826csqP NXwg== X-Gm-Message-State: AFqh2krHrqI5ol78TSWob5ASuagxbz4GFFcS4KOYHTK4d7ILSg5GZxqy fWPTCGQCiUGivjnSkWdij5I= X-Google-Smtp-Source: AMrXdXu3fM1fiRO/yonXcZWRuPbqRsjLpJpyiPS1Um30jNnWnjUPc6ShfhYMtmQZ5dYeiLpt1WzBkA== X-Received: by 2002:a17:907:88cb:b0:7bf:1072:2246 with SMTP id rq11-20020a17090788cb00b007bf10722246mr15166838ejc.38.1672051680909; Mon, 26 Dec 2022 02:48:00 -0800 (PST) Received: from pali ([2a02:2b88:6:5cc6::2f]) by smtp.gmail.com with ESMTPSA id p24-20020a17090653d800b007c0c679ca2fsm4648146ejo.26.2022.12.26.02.47.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 26 Dec 2022 02:48:00 -0800 (PST) Date: Mon, 26 Dec 2022 11:47:58 +0100 From: Pali =?utf-8?B?Um9ow6Fy?= To: binutils@sourceware.org, gcc@gcc.gnu.org, mingw-w64-public@lists.sourceforge.net Subject: Re: Problems when building NT kernel drivers with GCC / LD Message-ID: <20221226104758.ymu4vzkv7kl5jeqv@pali> References: <20221030000611.ytfadi4f2xcvodey@pali> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20221030000611.ytfadi4f2xcvodey@pali> User-Agent: NeoMutt/20180716 X-Spam-Status: No, score=-1.5 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Hello! I would like to remind this thread for gcc/binutils developers. Most of these issues are still present and cause problems for compiling native PE binary. If you have questions or you need any other information please let me know. On Sunday 30 October 2022 02:06:11 Pali Rohár wrote: > Hello! > > I tried to develop simple NT kernel driver and build it via GNU GCC, LD > and mingw-w64 ecosystem but due to issues with compiler and linker, it > is not possible to generate final .sys binary without adding workarounds > or postprocessing resulted PE .sys binary. > > I'm sending this email to all parties (binutils = linker, gcc = compiler, > mingw-w64 = runtime) which are involved in building process of NT kernel > driver (which is just native PE binary) and I would like to describe > existing issues and ask if you can come up with fixes. > > For demonstration I created very simple NT kernel driver which can be > compiled by MSVC compiler without any issues, so you can directly look > at the code and play with it: https://github.com/pali/secure-giveio > I have there also GNUmakefile which uses GNU tools for compilation and > tries to workaround issues. > > Here is the list of those GCC / LD issues which I observed during > development and compilation of NT kernel drivers: > > * GCC does not support __declspec(code_seg("segname")) declarator for > specifying name of PE/COFF segment name. But instead GCC supports > different syntax __declspec(section("segname")) for this thing. > > I thought that GCC added __declspec support for compatibility with > other PE/COFF compilers. But because declarators are different it just > means that __declspec segment name is not compatible neither with MSVC. > > If the GCC's intention of __declspec is compatibility support then it > would be really really useful to have support for __declspec(code_seg > instead of custom __declspec(section syntax supported only by GCC. > > As a workaround to have driver compilable by both MSVC and GCC it is > needed to add #ifdef for GCC compiler. > > * LD --dynamicbase is not working correctly. If used for PE executables > (not dynamic libraries) then it does *not* generate relocation info. > And without relocation info in PE binary, it is not possible to > relocate base address. Which makes dynamic base non-working. > > As a workaround GCC -pie can be used to generate relocation info (but > it is buggy too, see below). > > * GCC -pie is unusable. It automatically generates export symbol table > even when PE binary must not export anything. This applies for Native > PE executables used as NT kernel .sys drivers. Normally only dynamic > libraries export symbols, so by default for executables should not > symbol table. Or at least there should be a flag which can disable > doing it. > > I tried to workaround it via LD --exclude-all-symbols, but it is also > not usable, see below. > > * LD --exclude-all-symbols has issues for Native PE executables. It > causes generation of empty export table and puts name of the output > executable/driver (-o) as name of the export library. PE executables > which are in shared address space (e.g. NT driver executables) should > really do not be treated as libraries with library name (unless > explicitly asked for such thing). > > As a workaround I had to create a custom linker script which discards > that nonsense export table by completely dropping .edata section. > > * LD puts discardable init sections in the middle of the PE binary. This > is really stupid as loaded PE binary waste memory space. Discardable > init sections should be at the end of the PE binary. > > As a workaround I used custom linker script. > > * GCC or LD (not sure who) sets memory alignment characteristics > (IMAGE_SCN_ALIGN_MASK) into the sections of PE executable binary. > These characteristics should be only in COFF object files, not > executable binaries. Specially they should not be in NT kernel > drivers. > > * GCC or LD (not sure who) sets data characteristics > (IMAGE_SCN_CNT_INITIALIZED_DATA) for executable PE code sections. > Code sections should not be really marked as data, only as a code > (IMAGE_SCN_CNT_CODE). > > * GCC or LD (not sure who) sets memory writable characteristics > (IMAGE_SCN_MEM_WRITE) into the read-only resources PE sections. > Read-only sections of final PE executable really should not marked as > writable. > > * GCC or LD (not sure who) does *not* set memory discardable > characteristic (IMAGE_SCN_MEM_DISCARDABLE) for sections used only > during initial phase in NT kernel driver PE executables. This applies > for .idata, INIT and .rsrc sections. Without that characteristic there > is wasting of kernel memory. > > * GCC or LD (not sure who) does *not* set memory not_paged > characteristics (IMAGE_SCN_MEM_NOT_PAGED) for PE sections which must > not be paged in NT kernel driver executables. Basically most sections > should must not be paged unless explicitly asked/marked. By default > just section with name PAGE could be paged and therefore only this > section does not have to have IMAGE_SCN_MEM_NOT_PAGED. > > Last five issues I was not able to workaround neither via gcc or ld > flags and neither via linker script. For example MSVC link.exe linker > has switch /SECTION: which can be used to specify above characteristics > specific section. But whatever I tried to do in GNU linker script, I was > not able to set and fix those characteristics. For this reason I wrote > custom application which post-process built PE executable and fix > section characteristics, which GNU GCC/LD generated incorrectly. > > Then I have there rather small but sometimes annoying objcopy issue. > objcopy does not respect --disable-deterministic-archives or > --preserve-dates switches and always deletes PE date/timestamp from > executable. I was not able to find any switch which can tell objcopy to > preserve PE date/timestamp. LD has flag --insert-timestamp for this > thing, and this LD switch is working. > > > Could you please look at those issues? Is there something which can be > done to fix them? Because it is really stop-blocker for building even > simple NT kernel drivers via open source GNU tools. Basically one main > problem - generate relocation info for native executable - just reveal > chain of other issues. > > NT kernel .sys drivers are just simple Native PE executables (like > ordinary .exe executables) but with relocation info (like .dll > libraries) with fixed entry point, linked to ntoskrnl and have some > characteristics. > > Following gcc flags produce such executable (but with above issues): > > -Wl,--subsystem,native > -Wl,--dynamicbase -Wl,--nxcompat > -Wl,--image-base,0x10000 -Wl,--stack,0x40000 > -Wl,--section-alignment,0x1000 -Wl,--file-alignment,0x200 > -Wl,--disable-auto-import -Wl,--disable-stdcall-fixup > -nostartfiles -nodefaultlibs -nostdlib > -lntoskrnl > > Note that entry point is always stdcall "DriverEntry" function. And > because of symbol mangling, its symbol name is "_DriverEntry@8" for IX86 > and "DriverEntry" for AMD64. LD switch --entry= takes symbol name, not > function name. So it would be a nice feature to allow specifying entry > point via GCC/LD also as function name (without mangling) to have just > > -Wl,--entry=DriverEntry > > parameter for gcc for all 32-bit and 64-bit builds. > > And also it would be a nice to have some GCC flag which sets all above > flags required for compiling NT kernel driver. Like there is -mdll for > compiling DLL libraries or -mwindows for generating GUI WIN32 > executables. For example MSVC link.exe has for this switch /DRIVER. > > If you have some questions then please let me know. I think that it > would be really useful if GNU tools would be able to build NT kernel > drivers without needs for hacks.