Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Is it possible to compile a Go program without jump tables ?

548 views
Skip to first unread message

Karolina GORNA

unread,
Nov 27, 2024, 8:49:02 AM11/27/24
to golang-nuts
Hello,

I wondered if there is a similar command to gcc -fno-jump-tables -o output_file source_file.c to compile Go code without jump tables but only with if/else statements (binary search) please ?

Thank you

Les informations contenues dans ce message électronique ainsi que celles contenues dans les documents attachés sont strictement confidentielles et sont destinées à l'usage exclusif du (des) destinataire(s) nommé(s).
Toute divulgation, distribution ou reproduction, même partielle, en est strictement interdite sauf autorisation écrite et expresse de l’émetteur.
Si vous recevez ce message par erreur, veuillez le notifier immédiatement à son émetteur par retour, et le détruire ainsi que tous les documents qui y sont attachés.

The information contained in this email and in any document enclosed is strictly confidential and is intended solely for the use of the individual or entity to which it is addressed.
Partial or total disclosure, distribution or reproduction of its contents is strictly prohibited unless expressly approved in writing by the sender.
If you have received this communication in error, please notify us immediately by responding to this email, and then delete the message and its attached files from your system.

Ian Lance Taylor

unread,
Nov 27, 2024, 4:42:14 PM11/27/24
to Karolina GORNA, golang-nuts
On Wed, Nov 27, 2024 at 5:48 AM 'Karolina GORNA' via golang-nuts
<golan...@googlegroups.com> wrote:
>
> I wondered if there is a similar command to gcc -fno-jump-tables -o output_file source_file.c to compile Go code without jump tables but only with if/else statements (binary search) please ?

Sorry, there is no such option for the usual Go compiler.

Why do you want it?

Ian

Keith Randall

unread,
Nov 27, 2024, 7:48:29 PM11/27/24
to golang-nuts
Passing the -N flag will disable optimizations, which includes jump tables.

Karolina GORNA

unread,
Nov 28, 2024, 4:13:19 AM11/28/24
to golang-nuts
Hello everyone,

Thank you @Keith for the suggestion. I tried with "go build -gcflags='-N -l''" but I still have jump tables like "switchD_004010a2::switchdataD_004bc900"  with cases like switchD_004010a2::caseD_11 ; switchD_004010a2::caseD_12... that are in the .rodata section.

@Ian, ok I understand thank you. I am working on Go binary analysis and this feature would help a lot.

Best

Lin Lin

unread,
Nov 28, 2024, 7:38:49 PM11/28/24
to Karolina GORNA, golang-nuts
I assume you can rewrite the code from switch to if/else before compiling with go/ast package. If that is not your case, hacking the go compiler is a harder solution, you probably don't want to do that.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/golang-nuts/af196a67-a159-4c3a-8636-ef2d4941ae85n%40googlegroups.com.

Keith Randall

unread,
Nov 28, 2024, 8:49:52 PM11/28/24
to golang-nuts
On Thursday, November 28, 2024 at 4:38:49 PM UTC-8 Lin Lin wrote:
I assume you can rewrite the code from switch to if/else before compiling with go/ast package. If that is not your case, hacking the go compiler is a harder solution, you probably don't want to do that.

On Thu, 28 Nov 2024 at 17:12, 'Karolina GORNA' via golang-nuts <golan...@googlegroups.com> wrote:
Hello everyone,

Thank you @Keith for the suggestion. I tried with "go build -gcflags='-N -l''" but I still have jump tables like "switchD_004010a2::switchdataD_004bc900"  with cases like switchD_004010a2::caseD_11 ; switchD_004010a2::caseD_12... that are in the .rodata section.


Those don't sound like jump tables generated by the Go compiler. Does your program use cgo? Might they be from the C compiler?

Ian Lance Taylor

unread,
Nov 29, 2024, 12:39:02 AM11/29/24
to Karolina GORNA, golang-nuts
On Thu, Nov 28, 2024, 1:13 AM 'Karolina GORNA' via golang-nuts <golan...@googlegroups.com> wrote:

@Ian, ok I understand thank you. I am working on Go binary analysis and this feature would help a lot.

Out of curiosity, why do you want to do binary analysis on a program if you can ask for specific options to be used when building?  Why not just do source analysis, for which there are a bunch of good tools available? 

Ian

Karolina GORNA

unread,
Nov 29, 2024, 5:58:01 AM11/29/24
to golang-nuts
Hello everyone,

@Lin thank you for your feedback. However, I don't want to add a constraint on rewriting switch cases in if/else, I would be happy that the compiler can handle it at its end. For instance, GCC is able to remove jump tables even when there are switch cases in the source code with the option "-fno-jump-tables".

@Keith, the example I took was the simple Go code below, so no cgo involved. I built it with the command go build -gcflags='-N -l'  . . I analyzed the binary in Ghidra and I saw the switch tables I mentioned (being actually jump tables) in the .rodata section.
--> However, I figured out that by using the command go build -o <bin-name> -compiler=gccgo -gccgoflags='-fno-jump-tables' . , I successfully get a binary of the same code without jump tables in the .rodata section. The issue with GCCGO is that it doesn't handle Go functionalities about Go1.18 (see https://www.mail-archive.com/debian-b...@lists.debian.org/msg1983336.html) so it's quite limiting.
----------------------------------------------
package main

import "fmt"

func main() {
    x := 10
    switch x {
    case 1:
        fmt.Println("One")
    case 5:
        fmt.Println("Five")
    case 10:
        fmt.Println("Ten")
    default:
        fmt.Println("Other")
    }
}

----------------------------------------------

@Ian, I'm working on bug detection, and there seems to be more granularity and therefore more accuracy in analyzing low-level code than source code.

Best,
Karolina

Keith Randall

unread,
Nov 29, 2024, 8:16:20 PM11/29/24
to golang-nuts
Hmm, that's strange. I am not seeing that behavior.
Could you paste the *exact* commands you used to build your program here? Include GOARCH, GOOS, Go version, and anything else relevant.
How are you determining that there are are still jump tables? Please post the exact commands you used to determine that also.

One thing to try is to use "-gcflags=all=-N -l" instead of just "-gcflags=-N -l".

Karolina GORNA

unread,
Dec 2, 2024, 5:25:22 AM12/2/24
to golang-nuts
Hello Keith,

Thank you for your curiosity.

This is the procedure I follow :
  1. I have written the test program main.go below in the directory switch-go
  2. I use the command GOARCH=amd64 GOOS=linux go build -gcflags=all='-N -l' . with "go version go1.23.3 linux/amd64".
  3. I open the produced binary switch-go in the emulator tool of Ghidra, selecting the Golang compiler and launching the default analysis.
  4. In the Symbol Tree, I search for "switch" key world, and I find switch tables in the .rodata section, which are actually the jump tables I don't want to have.
Following the same procedure with go1.23.3 linux/amd64 and GCCGO 14.2.0 (Ubuntu 14.2.0-4ubuntu2~24.04) , but with the command GOARCH=amd64 GOOS=linux go build -buildvcs=false -compiler=gccgo -gccgoflags='-fno-jump-tables' . , I don't have any switch tables (more precisely, jump tables) in the .rodata section (where there are supposed to be if they exist). But again, GCCGO currently doesn't support functionalities for Go above 1.18. 

Best,
Karolina

PS : I know I don't need to specify GOARCH=amd64 GOOS=linux in the command but I have included them for the purpose of this debugging discussion.

switch-go/main.go
----------------------------------------------
package main

import "fmt"

func main() {
    x := 10
    switch x {
    case 1:
        fmt.Println("One")
    case 5:
        fmt.Println("Five")
    case 10:
        fmt.Println("Ten")
    default:
        fmt.Println("Other")
    }
}
----------------------------------------------

Keith Randall

unread,
Dec 2, 2024, 2:47:31 PM12/2/24
to golang-nuts
Ah, I see, there are still a few left in the runtime. The runtime forces optimizations on even when -N is used.

So no, I don't think you can do what you want (without hacking the compiler to turn jump tables off completely.)

Karolina GORNA

unread,
Dec 3, 2024, 4:09:29 AM12/3/24
to golang-nuts
I understand, thank you.

Andrey Bokhanko

unread,
Dec 3, 2024, 9:49:54 AM12/3/24
to golang-nuts
понедельник, 2 декабря 2024 г. в 13:25:22 UTC+3, Karolina GORNA:
switch-go/main.go
----------------------------------------------
package main

import "fmt"

func main() {
    x := 10
    switch x {
    case 1:
        fmt.Println("One")
    case 5:
        fmt.Println("Five")
    case 10:
        fmt.Println("Ten")
    default:
        fmt.Println("Other")
    }
}
 
Karolina, in this specific test case the whole switch got optimized out, as it's clear it always computes to 10, so only one case remains.

Andrey

Karolina GORNA

unread,
Dec 3, 2024, 10:24:09 AM12/3/24
to golang-nuts

Yes thank you Andrey,
I noticed this shortly after sending the example in the email. I redid the procedure on the code below which is not optimized by the Go compiler, and I get the same conclusions as before, you can check.

Best,
Karolina

switch-go-improved/main.go
----------------------------------------------
package main

import (
    "fmt"
    "os"
    "strconv"
)

func main() {
    // this is so that the Go compiler doesn't optimize drasticvally the code
    if os.Args[1] == "" {
        fmt.Println("Please provide a number (1, 5, 10, or other)")
        os.Exit(1)
    }
    x, err := strconv.Atoi(os.Args[1])
    if err != nil {
        fmt.Println("Invalid number")
        os.Exit(1)

    }

    switch x {
    case 1:
        fmt.Println("One")
    case 5:
        fmt.Println("Five")
    case 10:
        fmt.Println("Ten")
    default:
        fmt.Println("Other")
    }
}

----------------------------------------------
Reply all
Reply to author
Forward
0 new messages