2

I've this block of code

__asm
{
    mov eax, fs:[18h]
    mov eax, [eax + 30h]
    mov eax, [eax + 0Ch]
    mov pmInfo, eax
}

This is supposed to retrieve the TEB in the first line, the PEB in the second line, and the last one is a struct that contains process module information.

typedef struct _ProcessModuleInfo
{
    unsigned int size;
    unsigned int initialized;
    HANDLE SsHandle;
    LIST_ENTRY LoadOrder;
    LIST_ENTRY InitOrder;
    LIST_ENTRY MemoryOrder;
} ProcessModuleInfo, *pProcessModuleInfo;

My question is, how do I convert that piece of assembly to codeblocks' GCC compiler?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
Srdja Nikolic
  • 53
  • 1
  • 8
  • You'd use a [GCC extended assembler template](https://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Extended-Asm.html). But that is very non trivial if you are new to _GCC_. Unless you know what you are doing with GCC inline, it is very hard to get right. You are probably better off placing that code in an assembler file as a function and linking it against your _C_ code. – Michael Petch Jun 07 '16 at 19:26
  • Thanks for replying. I've checked out plenty of links, but as you said it's indeed very non trivial. What I'm really looking for right now Is just a quick solution for this particular problem. I've never used assembler file linking, but well I can research how that's done. If anyone has any other quick solutions or the code itself for GCC I'd be very grateful! – Srdja Nikolic Jun 07 '16 at 19:31
  • Thank you! It seems to work. – Srdja Nikolic Jun 07 '16 at 20:01
  • Are you porting your code to non-Windows? If so, are you sure that the same instructions are even what you want? e.g. you should probably use C/C++ syntax for thread-local storage, and let the compiler generate the access to the thread-local storage block. – Peter Cordes Jun 07 '16 at 21:58
  • 1
    @PeterCordes : I may have incorrectly assumed that he was still targeting Windows and was using Codeblocks on Windows (that uses the TDM-GCC compiler). Since I saw no mention of Linux I figured he was moving to a different compiler on the Win32 platform (MSVC to Win32/TDM GCC). After the fact my assumption may have been correct if this works for him, I'd expect a segfault when trying to dereference the pointers on Linux) – Michael Petch Jun 08 '16 at 00:18

1 Answers1

2

You can learn more about GCC assembler templates in the GCC documentation. Peter Cordes has a Stackoverflow answer with a list of inline assembler if you wish to learn more. MSVC and GCC differ greatly. GCC has no knowledge of what a template does or the instructions executes. GCC instead does substitutions based upon a list of constraints - input, output, and clobber.

A GCC extended assembler template that would be a close approximation to the MSVC inline assembler could look like:

__asm__ (
    "mov %%fs:0x18, %0\n\t"
    "mov 0x30(%0), %0\n\t"
    "mov 0x0C(%0), %0\n\t"
    : "=r"(pmInfo));

In your case you need a single register to use for the internal usage. It doesn't need to be EAX but can be any register GCC has available. We use an output constraint of "=r" that says we want GCC to choose an available register. We reference the first (and in this case the only one) constraint via %0 in the assembler template. "=r"(pmInfo) on the constraint says that when the instructions in the template are complete the value in the register chosen will be placed into pmInfo .

GCC extended assembler is a tricky thing to work with, and very easy to get wrong. You might be better off creating an assembler file with a function that returns a pointer to a ProcessModuleInfo structure. This eliminates the need to understand GCC's extended assembler templates, and deal with its intricacies.

Stackoverflow user DavidWohlferd wrote a GCC wiki article giving reasons why using GCC inline assembler should be avoided if possible.


If the %0 looks a bit confusing, each of the input and output operands can be given a symbolic name that can be used as an alternative instead of % and a number in the template. The code could have looked like this:

__asm__ (
    "mov %%fs:0x18, %[tempreg]\n\t"
    "mov 0x30(%[tempreg]), %[tempreg]\n\t"
    "mov 0x0C(%[tempreg]), %[tempreg]\n\t"
    : [tempreg]"=r"(pmInfo));

The [tempreg] in square brackets gives the operand a name as alternative to using an ordinal position. This makes it a bit easier to read the template as well.

Community
  • 1
  • 1
Michael Petch
  • 46,082
  • 8
  • 107
  • 198
  • Would it help the optimizer to do more of that in C? e.g. just do the load that needs the segment override? Although if you need to treat `fs:[18h]` as `volatile`, then you might as well use `asm volatile` for the whole chain of loads. And if you don't use `asm volatile`, then the compiler should be able to hoist the whole chain of loads out of loops. So there's probably no benefit to letting the compiler see the next two loads in the chain. IIRC, gcc doesn't really do instruction scheduling for x86, because it assumes out-of-order CPUs. – Peter Cordes Jun 07 '16 at 22:03
  • If the OP had the data structures to traverse through I would just get the original value at `fs:0x18` and do the indirection in _C_.The OP didn't provide any data structures for the 2 intermediate data structures (like the TEB), and the _C_ code you produce looks pretty messy. I produced a version that did a pile of casting (and pointer indexing on either a void or uint32_t*) and in the way of readability-this was easier and to follow.Since the OP requested a straight conversion, and only wanted a solution that worked (I made such an inquiry under the question that gave a response)I delivered – Michael Petch Jun 07 '16 at 22:49
  • You could just return `struct _ProcessModuleInfo ***` or something, and do pointer arithmetic. Then you don't need any casting, and C thinks it's just indexing arrays of pointers. – Peter Cordes Jun 07 '16 at 22:54
  • I actually produced the _ASM_ as a comment (I deleted it earlier) with no intention of producing an answer, sinc ei was unsure if it even worked as expected. – Michael Petch Jun 07 '16 at 22:54
  • Does that `fs:0x18` mean anything to you for Windows? I've never looked into the details of what Linux stores in `gs:[]` for 32bit TLS, or `fs:[]` for 64bit TLS, and I have no idea what Windows does. – Peter Cordes Jun 07 '16 at 22:56
  • 1
    @PeterCordes : FS is a segment with a base that points to the Win32 Thread Information Block. fs:0x18 contains a pointer to the Thread Environment Block. The pointer in the TEB at offset 0x30 is a pointer to the Process Environment Block (PEB). The PEB contains a pointer to the Process Module Information structure at offset 0x0C. – Michael Petch Jun 07 '16 at 23:02
  • 1
    PeterCordes : On a side note more recent versions of MSVC have the intrinsic `__readfsdword` (but it wasn't always available) so code targeting older MSVCs would use inline assembler. `__readfsdword(0x18)` would read the DWORD value at `fs:0x18`. I actually went looking and I didn't see one for _GCC_ that I could guarantee would work. I don't have at present a version of his TDM GCC compiler to test anything with. In the MSVC Windows environment most of the data structures (all of the ones I mentioned) are in _C_ header files. In that case it is very convenient to __readfsdword and dereference – Michael Petch Jun 07 '16 at 23:08
  • Thanks for the help people, It helped a lot. – Srdja Nikolic Jun 08 '16 at 00:03
  • 1
    @PeterCordes: Scrolling back I missed your comment and noticed you mentioned something like `struct _ProcessModuleInfo ***` . One of the variants I had was `pProcessModuleInfo **pTIB; __asm__ ( "mov %%fs:0x18, %[TIB]\n\t" : [TIB]"=r"(pTIB)); pmInfo = pTIB[12][3];` But that is pretty hackish mainly because we are taking advantage of the fact that all the offsets are evenly div by 4.Don't think the compiler will be able to do any better with it than the original and as it goes for future maintainers they might scratch their head at first. I find that less readable. – Michael Petch Jun 08 '16 at 01:19