From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-ej1-x62e.google.com (mail-ej1-x62e.google.com [IPv6:2a00:1450:4864:20::62e]) by sourceware.org (Postfix) with ESMTPS id CFA9F3858D35 for ; Sun, 30 Oct 2022 00:06:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org CFA9F3858D35 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-x62e.google.com with SMTP id ud5so21294701ejc.4 for ; Sat, 29 Oct 2022 17:06:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=user-agent:content-disposition:mime-version:message-id:subject:to :from:date:from:to:cc:subject:date:message-id:reply-to; bh=VpM9UGWzGsGoe8Rux7s4FrqqmOOM6LcCJtwbHNYDXMs=; b=oKA7xTSrAYEivCGtjE0g8XyFdFPnWKwv87rOeLQZ+dBEaVZPjJhTg439Vb23gm+11E sYTw5EFfKYYxVV+FV32md09XWpjzN6ekivOdt7y1O1hl9ordVr0bZYy57r2Jz5i8CGP3 3Tuul8OD2SuFXS4k3vs+K9W9iEFVFKVEd6NLEEoCLVSZHFnGtNozf78rzi5oKdJ64irt Nnei/r/kUfDr/wfHen9b3HHBhLaNlAyOURIk3b3f10UDibe2iLqIoeMr9i/ZliqpvptK QKBc5oFdeUIf7trVAkKnFCHL3TesBNQPnrcA/drFCNSob6X06Tdj6OAmLrtyoBTdN2X4 Di0g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=user-agent:content-disposition:mime-version:message-id:subject:to :from:date:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=VpM9UGWzGsGoe8Rux7s4FrqqmOOM6LcCJtwbHNYDXMs=; b=q4mgD7Nvblw/JgKEScxB1sXbVjqGp/5i97lSotePxwAYgz0ycpVEdDCzw6KYHkxPuG da8LSdSEpcdN14HyS7l6d4PpaFeKhZXtBsyXGog5fyZ8l1e8xYKH+hEVCbaUE3RwOa+y 18yjZJj39oXTp7u6381gyqPcR6QZGSAYEmve9HD/HeMvzouasqmp5+WgC602Jn+0yMx7 puu7c8GlEJ6pK8bTU4JEWNR4G7KttHI5GK0KwPuD8+MQOGM2t8/EBBglkXaP/inZQkXC iLh0oxIQDVY0dCjdcxDoFLx7JHaqLf5U2INVSCCJxctOq/xjQqClXkO02WDz0ar65Vgc BYhQ== X-Gm-Message-State: ACrzQf1YmmxwBpSdU6OkQW5YKp4nBWKuIL9aRuQeHt4UTf4jpN788FD8 pxKMjniphZKH1VdbUEnFh2Y= X-Google-Smtp-Source: AMsMyM56NuVEc/KakJTkqyHnnk6sOeoGZ1YKo+tOV3+xgggvA70jUaQBKr4GKs4fQysKdeGoPGzL7g== X-Received: by 2002:a17:907:7ea6:b0:791:81f4:b0e3 with SMTP id qb38-20020a1709077ea600b0079181f4b0e3mr5970409ejc.164.1667088373356; Sat, 29 Oct 2022 17:06:13 -0700 (PDT) Received: from pali ([2a02:2b88:6:5cc6::2f]) by smtp.gmail.com with ESMTPSA id bf12-20020a0564021a4c00b0045723aa48ccsm1373299edb.93.2022.10.29.17.06.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 29 Oct 2022 17:06:12 -0700 (PDT) Date: Sun, 30 Oct 2022 02:06:11 +0200 From: Pali =?utf-8?B?Um9ow6Fy?= To: binutils@sourceware.org, gcc@gcc.gnu.org, mingw-w64-public@lists.sourceforge.net Subject: Problems when building NT kernel drivers with GCC / LD Message-ID: <20221030000611.ytfadi4f2xcvodey@pali> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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 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.